api_docs: Fix missing content from API documentation.

This commit is contained in:
Vector73
2024-06-20 19:39:32 +05:30
committed by Tim Abbott
parent 9e0a3bebfd
commit b285e631e9
2 changed files with 100 additions and 24 deletions

View File

@@ -1,6 +1,6 @@
import json import json
import re import re
from typing import Any, List, Mapping, Sequence from typing import Any, Dict, List, Mapping, Sequence
import markdown import markdown
from django.utils.html import escape as escape_html from django.utils.html import escape as escape_html
@@ -36,6 +36,13 @@ OBJECT_DETAILS_TEMPLATE = """
</ul> </ul>
""".strip() """.strip()
ONEOF_OBJECT_DETAILS_TEMPLATE = """
<p>An object with the following fields:</p>
<ul>
{values}
</ul>
""".strip()
OBJECT_LIST_ITEM_TEMPLATE = """ OBJECT_LIST_ITEM_TEMPLATE = """
<li> <li>
<code>{value}</code>: <span class=api-field-type>{data_type}</span> {required} {description}{object_details} <code>{value}</code>: <span class=api-field-type>{data_type}</span> {required} {description}{object_details}
@@ -49,6 +56,17 @@ OBJECT_DESCRIPTION_TEMPLATE = """
OBJECT_CODE_TEMPLATE = "<code>{value}</code>".strip() OBJECT_CODE_TEMPLATE = "<code>{value}</code>".strip()
ONEOF_DETAILS_TEMPLATE = """
<p>This parameter must be one of the following:</p>
<ol>
{values}
</ol>
""".strip()
ONEOF_LIST_ITEM_TEMPLATE = """
<li>{item}</li>
""".strip()
class MarkdownArgumentsTableGenerator(Extension): class MarkdownArgumentsTableGenerator(Extension):
@override @override
@@ -100,6 +118,24 @@ class APIArgumentsTablePreprocessor(Preprocessor):
done = True done = True
return lines return lines
def render_oneof_block(self, object_schema: Dict[str, Any], name: str) -> str:
md_engine = markdown.Markdown(extensions=[])
content = ""
for element in object_schema["oneOf"]:
if "items" in element and "properties" in element["items"]:
content += ONEOF_LIST_ITEM_TEMPLATE.format(
item=self.render_object_details(element["items"], str(name), True)
)
elif "properties" in element:
content += ONEOF_LIST_ITEM_TEMPLATE.format(
item=self.render_object_details(element, str(name), True)
)
elif "description" in element:
content += ONEOF_LIST_ITEM_TEMPLATE.format(
item=md_engine.convert(element["description"])
)
return ONEOF_DETAILS_TEMPLATE.format(values=content)
def render_parameters(self, parameters: Sequence[Parameter]) -> List[str]: def render_parameters(self, parameters: Sequence[Parameter]) -> List[str]:
lines = [] lines = []
@@ -159,6 +195,8 @@ class APIArgumentsTablePreprocessor(Preprocessor):
object_block = self.render_object_details(object_schema["items"], str(name)) object_block = self.render_object_details(object_schema["items"], str(name))
elif "properties" in object_schema: elif "properties" in object_schema:
object_block = self.render_object_details(object_schema, str(name)) object_block = self.render_object_details(object_schema, str(name))
elif "oneOf" in object_schema:
object_block = self.render_oneof_block(object_schema, str(name))
lines.append( lines.append(
API_PARAMETER_TEMPLATE.format( API_PARAMETER_TEMPLATE.format(
@@ -174,7 +212,9 @@ class APIArgumentsTablePreprocessor(Preprocessor):
return lines return lines
def render_object_details(self, schema: Mapping[str, Any], name: str) -> str: def render_object_details(
self, schema: Mapping[str, Any], name: str, oneof: bool = False
) -> str:
md_engine = markdown.Markdown(extensions=[]) md_engine = markdown.Markdown(extensions=[])
li_elements = [] li_elements = []
@@ -227,6 +267,8 @@ class APIArgumentsTablePreprocessor(Preprocessor):
details = "" details = ""
if "object" in data_type and "properties" in object_values[value]: if "object" in data_type and "properties" in object_values[value]:
details += self.render_object_details(object_values[value], str(value)) details += self.render_object_details(object_values[value], str(value))
elif "oneOf" in object_values[value]:
details += self.render_oneof_block(object_values[value], str(value))
li = OBJECT_LIST_ITEM_TEMPLATE.format( li = OBJECT_LIST_ITEM_TEMPLATE.format(
value=value, value=value,
@@ -237,11 +279,15 @@ class APIArgumentsTablePreprocessor(Preprocessor):
) )
li_elements.append(li) li_elements.append(li)
if oneof:
object_details = OBJECT_DETAILS_TEMPLATE.format( object_details = ONEOF_OBJECT_DETAILS_TEMPLATE.format(
argument=name, values="\n".join(li_elements),
values="\n".join(li_elements), )
) else:
object_details = OBJECT_DETAILS_TEMPLATE.format(
argument=name,
values="\n".join(li_elements),
)
return object_details return object_details

View File

@@ -147,6 +147,39 @@ class APIReturnValuesTablePreprocessor(Preprocessor):
+ description + description
) )
def render_oneof_block(self, object_schema: Dict[str, Any], spacing: int) -> List[str]:
ans = []
block_spacing = spacing
for element in object_schema["oneOf"]:
spacing = block_spacing
if "description" not in element:
# If the description is not present, we still need to render the rest
# of the documentation of the element shifted towards left of the page.
spacing -= 4
else:
# Add the specialized description of the oneOf element.
data_type = generate_data_type(element)
ans.append(self.render_desc(element["description"], spacing, data_type))
# If the oneOf element is an object schema then render the documentation
# of its keys.
if "properties" in element:
ans += self.render_table(element["properties"], spacing + 4)
if element.get("additionalProperties", False):
additional_properties = element["additionalProperties"]
if "description" in additional_properties:
data_type = generate_data_type(additional_properties)
ans.append(
self.render_desc(
additional_properties["description"], spacing + 4, data_type
)
)
if "properties" in additional_properties:
ans += self.render_table(
additional_properties["properties"],
spacing + 8,
)
return ans
def render_table(self, return_values: Dict[str, Any], spacing: int) -> List[str]: def render_table(self, return_values: Dict[str, Any], spacing: int) -> List[str]:
IGNORE = ["result", "msg", "ignored_parameters_unsupported"] IGNORE = ["result", "msg", "ignored_parameters_unsupported"]
ans = [] ans = []
@@ -165,16 +198,7 @@ class APIReturnValuesTablePreprocessor(Preprocessor):
return_values[return_value]["description"], spacing, data_type, return_value return_values[return_value]["description"], spacing, data_type, return_value
) )
) )
for element in return_values[return_value]["oneOf"]: ans += self.render_oneof_block(return_values[return_value], spacing + 4)
if "description" not in element:
continue
# Add the specialized description of the oneOf element.
data_type = generate_data_type(element)
ans.append(self.render_desc(element["description"], spacing + 4, data_type))
# If the oneOf element is an object schema then render the documentation
# of its keys.
if "properties" in element:
ans += self.render_table(element["properties"], spacing + 8)
continue continue
description = return_values[return_value]["description"] description = return_values[return_value]["description"]
data_type = generate_data_type(return_values[return_value]) data_type = generate_data_type(return_values[return_value])
@@ -198,6 +222,10 @@ class APIReturnValuesTablePreprocessor(Preprocessor):
return_values[return_value]["additionalProperties"]["properties"], return_values[return_value]["additionalProperties"]["properties"],
spacing + 8, spacing + 8,
) )
elif "oneOf" in return_values[return_value]["additionalProperties"]:
ans += self.render_oneof_block(
return_values[return_value]["additionalProperties"], spacing + 8
)
elif return_values[return_value]["additionalProperties"].get( elif return_values[return_value]["additionalProperties"].get(
"additionalProperties", False "additionalProperties", False
): ):
@@ -220,13 +248,15 @@ class APIReturnValuesTablePreprocessor(Preprocessor):
], ],
spacing + 12, spacing + 12,
) )
if ( if "items" in return_values[return_value]:
"items" in return_values[return_value] if "properties" in return_values[return_value]["items"]:
and "properties" in return_values[return_value]["items"] ans += self.render_table(
): return_values[return_value]["items"]["properties"], spacing + 4
ans += self.render_table( )
return_values[return_value]["items"]["properties"], spacing + 4 elif "oneOf" in return_values[return_value]["items"]:
) ans += self.render_oneof_block(
return_values[return_value]["items"], spacing + 4
)
return ans return ans
def generate_event_strings(self, event_data: EventData) -> List[str]: def generate_event_strings(self, event_data: EventData) -> List[str]: