openapi: Create markdown extension for rendering endpoint descriptions.

Add function in openapi.py to access endpoint descriptions written
in zulip.yaml. Use this function for creating a markdown extension
for rendering endpoint descriptions written in zulip.yaml.

We use this extension for a single endpoint to get test coverage.
This commit is contained in:
orientor 2020-04-28 15:43:46 +05:30 committed by Tim Abbott
parent cfe427b3f7
commit 64c6bab276
5 changed files with 77 additions and 5 deletions

View File

@ -1,9 +1,6 @@
# Add an emoji reaction
Add an [emoji reaction](/help/emoji-reactions) to a message.
`POST {{ api_url }}/v1/messages/{message_id}/reactions`
{generate_api_description(/messages/{message_id}/reactions:post)}
## Usage examples

View File

@ -0,0 +1,63 @@
import re
from markdown.extensions import Extension
from markdown.preprocessors import Preprocessor
from typing import Any, Dict, Optional, List
import markdown
from zerver.openapi.openapi import get_openapi_description
MACRO_REGEXP = re.compile(r'\{generate_api_description(\(\s*(.+?)\s*\))}')
class APIDescriptionGenerator(Extension):
def __init__(self, api_url: Optional[str]) -> None:
self.config = {
'api_url': [
api_url,
'API URL to use when rendering api links'
]
}
def extendMarkdown(self, md: markdown.Markdown, md_globals: Dict[str, Any]) -> None:
md.preprocessors.add(
'generate_api_description', APIDescriptionPreprocessor(md, self.getConfigs()), '_begin'
)
class APIDescriptionPreprocessor(Preprocessor):
def __init__(self, md: markdown.Markdown, config: Dict[str, Any]) -> None:
super().__init__(md)
self.api_url = config['api_url']
def run(self, lines: List[str]) -> List[str]:
done = False
while not done:
for line in lines:
loc = lines.index(line)
match = MACRO_REGEXP.search(line)
if match:
function = match.group(2)
text = self.render_description(function)
# The line that contains the directive to include the macro
# may be preceded or followed by text or tags, in that case
# we need to make sure that any preceding or following text
# stays the same.
line_split = MACRO_REGEXP.split(line, maxsplit=0)
preceding = line_split[0]
following = line_split[-1]
text = [preceding] + text + [following]
lines = lines[:loc] + text + lines[loc+1:]
break
else:
done = True
return lines
def render_description(self, function: str) -> List[str]:
description: List[str] = []
path, method = function.rsplit(':', 1)
description_dict = get_openapi_description(path, method)
description_dict = description_dict.replace('{{api_url}}', self.api_url)
description.extend(description_dict.splitlines())
return description
def makeExtension(*args: Any, **kwargs: str) -> APIDescriptionGenerator:
return APIDescriptionGenerator(*args, **kwargs)

View File

@ -79,6 +79,12 @@ def get_openapi_fixture(endpoint: str, method: str,
response = '200'
return (get_schema(endpoint, method, response)['example'])
def get_openapi_description(endpoint: str, method: str) -> str:
"""Fetch a description from the full spec object.
"""
description = openapi_spec.spec()['paths'][endpoint][method.lower()]['description']
return description
def get_openapi_paths() -> Set[str]:
return set(openapi_spec.spec()['paths'].keys())

View File

@ -818,7 +818,9 @@ paths:
/messages/{message_id}/reactions:
post:
description: |
Add an emoji reaction to a message.
Add an [emoji reaction](/help/emoji-reactions) to a message.
`POST {{ api_url }}/v1/messages/{message_id}/reactions`
parameters:
- $ref: '#/components/parameters/MessageId'
- name: emoji_name

View File

@ -12,6 +12,7 @@ from jinja2.exceptions import TemplateNotFound
import zerver.lib.bugdown.fenced_code
import zerver.lib.bugdown.api_arguments_table_generator
import zerver.lib.bugdown.api_code_examples
import zerver.lib.bugdown.api_description
import zerver.lib.bugdown.nested_code_blocks
import zerver.lib.bugdown.tabbed_sections
import zerver.lib.bugdown.help_settings_links
@ -126,6 +127,9 @@ def render_markdown_path(markdown_file_path: str,
extensions = extensions + [zerver.lib.bugdown.api_code_examples.makeExtension(
api_url=context["api_url"],
)]
extensions = extensions + [zerver.lib.bugdown.api_description.makeExtension(
api_url=context["api_url"],
)]
if not any(doc in markdown_file_path for doc in docs_without_macros):
extensions = extensions + [md_macro_extension]