usse/scrape/venv/lib/python3.10/site-packages/sphinx/util/docstrings.py

89 lines
2.9 KiB
Python
Raw Normal View History

2023-12-22 14:26:01 +00:00
"""Utilities for docstring processing."""
from __future__ import annotations
import re
import sys
from docutils.parsers.rst.states import Body
field_list_item_re = re.compile(Body.patterns['field_marker'])
def separate_metadata(s: str | None) -> tuple[str | None, dict[str, str]]:
"""Separate docstring into metadata and others."""
in_other_element = False
metadata: dict[str, str] = {}
lines = []
if not s:
return s, metadata
for line in prepare_docstring(s):
if line.strip() == '':
in_other_element = False
lines.append(line)
else:
matched = field_list_item_re.match(line)
if matched and not in_other_element:
field_name = matched.group()[1:].split(':', 1)[0]
if field_name.startswith('meta '):
name = field_name[5:].strip()
metadata[name] = line[matched.end():].strip()
else:
lines.append(line)
else:
in_other_element = True
lines.append(line)
return '\n'.join(lines), metadata
def prepare_docstring(s: str, tabsize: int = 8) -> list[str]:
"""Convert a docstring into lines of parseable reST. Remove common leading
indentation, where the indentation of the first line is ignored.
Return the docstring as a list of lines usable for inserting into a docutils
ViewList (used as argument of nested_parse().) An empty line is added to
act as a separator between this docstring and following content.
"""
lines = s.expandtabs(tabsize).splitlines()
# Find minimum indentation of any non-blank lines after ignored lines.
margin = sys.maxsize
for line in lines[1:]:
content = len(line.lstrip())
if content:
indent = len(line) - content
margin = min(margin, indent)
# Remove indentation from the first line.
if len(lines):
lines[0] = lines[0].lstrip()
if margin < sys.maxsize:
for i in range(1, len(lines)):
lines[i] = lines[i][margin:]
# Remove any leading blank lines.
while lines and not lines[0]:
lines.pop(0)
# make sure there is an empty line at the end
if lines and lines[-1]:
lines.append('')
return lines
def prepare_commentdoc(s: str) -> list[str]:
"""Extract documentation comment lines (starting with #:) and return them
as a list of lines. Returns an empty list if there is no documentation.
"""
result = []
lines = [line.strip() for line in s.expandtabs().splitlines()]
for line in lines:
if line.startswith('#:'):
line = line[2:]
# the first space after the comment is ignored
if line and line[0] == ' ':
line = line[1:]
result.append(line)
if result and result[-1]:
result.append('')
return result