Increase OAS description
Parce docstring of http handlers to increase OAS Remove the not expected definitions key in the OAS
This commit is contained in:
120
aiohttp_pydantic/oas/docstring_parser.py
Normal file
120
aiohttp_pydantic/oas/docstring_parser.py
Normal file
@@ -0,0 +1,120 @@
|
||||
"""
|
||||
Utility to extract extra OAS description from docstring.
|
||||
"""
|
||||
|
||||
import re
|
||||
import textwrap
|
||||
from typing import Dict
|
||||
|
||||
|
||||
class LinesIterator:
|
||||
def __init__(self, lines: str):
|
||||
self._lines = lines.splitlines()
|
||||
self._i = -1
|
||||
|
||||
def next_line(self) -> str:
|
||||
if self._i == len(self._lines) - 1:
|
||||
raise StopIteration from None
|
||||
self._i += 1
|
||||
return self._lines[self._i]
|
||||
|
||||
def rewind(self) -> str:
|
||||
if self._i == -1:
|
||||
raise StopIteration from None
|
||||
self._i -= 1
|
||||
return self._lines[self._i]
|
||||
|
||||
def __iter__(self):
|
||||
return self
|
||||
|
||||
def __next__(self):
|
||||
return self.next_line()
|
||||
|
||||
|
||||
def _i_extract_block(lines: LinesIterator):
|
||||
"""
|
||||
Iter the line within an indented block and dedent them.
|
||||
"""
|
||||
|
||||
# Go to the first not empty or not white space line.
|
||||
try:
|
||||
line = next(lines)
|
||||
except StopIteration:
|
||||
return # No block to extract.
|
||||
while line.strip() == "":
|
||||
try:
|
||||
line = next(lines)
|
||||
except StopIteration:
|
||||
return
|
||||
|
||||
# Get the size of the indentation.
|
||||
if (match := re.search("^ +", line)) is None:
|
||||
return # No block to extract.
|
||||
indent = match.group()
|
||||
yield line[len(indent) :]
|
||||
|
||||
# Yield lines until the indentation is the same or is greater than
|
||||
# the first block line.
|
||||
try:
|
||||
line = next(lines)
|
||||
except StopIteration:
|
||||
return
|
||||
while (is_empty := line.strip() == "") or line.startswith(indent):
|
||||
yield "" if is_empty else line[len(indent) :]
|
||||
try:
|
||||
line = next(lines)
|
||||
except StopIteration:
|
||||
return
|
||||
|
||||
lines.rewind()
|
||||
|
||||
|
||||
def _dedent_under_first_line(text: str) -> str:
|
||||
"""
|
||||
Apply textwrap.dedent ignoring the first line.
|
||||
"""
|
||||
lines = text.splitlines()
|
||||
other_lines = "\n".join(lines[1:])
|
||||
if other_lines:
|
||||
return f"{lines[0]}\n{textwrap.dedent(other_lines)}"
|
||||
return text
|
||||
|
||||
|
||||
def status_code(docstring: str) -> Dict[int, str]:
|
||||
"""
|
||||
Extract the "Status Code:" block of the docstring.
|
||||
"""
|
||||
iterator = LinesIterator(docstring)
|
||||
for line in iterator:
|
||||
if re.fullmatch("status\\s+codes?\\s*:", line, re.IGNORECASE):
|
||||
blocks = []
|
||||
lines = []
|
||||
for line_of_block in _i_extract_block(iterator):
|
||||
if re.search("^\\d{3}\\s*:", line_of_block):
|
||||
if lines:
|
||||
blocks.append("\n".join(lines))
|
||||
lines = []
|
||||
lines.append(line_of_block)
|
||||
if lines:
|
||||
blocks.append("\n".join(lines))
|
||||
|
||||
return {
|
||||
int(status.strip()): _dedent_under_first_line(desc.strip())
|
||||
for status, desc in (block.split(":", 1) for block in blocks)
|
||||
}
|
||||
return {}
|
||||
|
||||
|
||||
def operation(docstring: str) -> str:
|
||||
"""
|
||||
Extract all docstring except the "Status Code:" block.
|
||||
"""
|
||||
lines = LinesIterator(docstring)
|
||||
ret = []
|
||||
for line in lines:
|
||||
if re.fullmatch("status\\s+codes?\\s*:", line, re.IGNORECASE):
|
||||
for _ in _i_extract_block(lines):
|
||||
pass
|
||||
else:
|
||||
ret.append(line)
|
||||
return ("\n".join(ret)).strip()
|
||||
Reference in New Issue
Block a user