""" Google docstring parser for Python. """ from typing import Optional from liteyuki_autodoc.docstring.docstring import Docstring class Parser: ... class GoogleDocstringParser(Parser): _tokens = { "Args" : "args", "Arguments" : "args", "参数" : "args", "Return" : "return", "Returns" : "return", "返回" : "return", "Attribute" : "attribute", "Attributes" : "attribute", "属性" : "attribute", "Raises" : "raises", "Raise" : "raises", "引发" : "raises", "Example" : "example", "Examples" : "example", "示例" : "example", "Yields" : "yields", "Yield" : "yields", "产出" : "yields", "Requires" : "requires", "Require" : "requires", "需要" : "requires", "FrontMatter": "front_matter", "前言" : "front_matter", } def __init__(self, docstring: str, indent: int = 4): self.lines = docstring.splitlines() self.indent = indent self.lineno = 0 # Current line number self.char = 0 # Current character position self.docstring = Docstring() def match_token(self) -> Optional[str]: for token in self._tokens: if self.lines[self.lineno][self.char:].startswith(token): self.char += len(token) return self._tokens[token] return None def parse_args(self): """ 依次解析后面的参数行,直到缩进小于等于当前行的缩进 """ while line := self.match_next_line(): if ":" in line: name, desc = line.split(":", 1) self.docstring.add_arg(name.strip(), desc.strip()) else: self.docstring.add_arg(line.strip()) def parse_return(self): """ 解析返回值行 """ if line := self.match_next_line(): self.docstring.add_return(line.strip()) def parse_raises(self): """ 解析异常行 """ while line := self.match_next_line(): if ":" in line: name, desc = line.split(":", 1) self.docstring.add_raise(name.strip(), desc.strip()) else: self.docstring.add_raise(line.strip()) def parse_example(self): """ 解析示例行 """ while line := self.match_next_line(): if ":" in line: name, desc = line.split(":", 1) self.docstring.add_example(name.strip(), desc.strip()) else: self.docstring.add_example(line.strip()) def parse_attrs(self): """ 解析属性行 """ while line := self.match_next_line(): if ":" in line: name, desc = line.split(":", 1) self.docstring.add_attrs(name.strip(), desc.strip()) else: self.docstring.add_attrs(line.strip()) def match_next_line(self) -> Optional[str]: """ 在一个子解析器中,解析下一行,直到缩进小于等于当前行的缩进 Returns: """ while (self.lineno + 1) < len(self.lines): line = self.lines[self.lineno + 1] if line.startswith(" " * self.indent): line = line[self.indent:] self.lineno += 1 return line else: self.lineno += 1 return None self.lineno += 1 return None def parse(self) -> Docstring: """ 逐行解析,直到遇到EOS 最开始未解析到的内容全部加入desc Returns: """ add_desc = True while self.lineno < len(self.lines): token = self.match_token() if token is None and add_desc: self.docstring.add_desc(self.lines[self.lineno].strip()) if token is not None: add_desc = False match token: case "args": self.parse_args() case "return": self.parse_return() case "attribute": self.parse_attrs() case "raises": self.parse_raises() case "example": self.parse_example() case _: self.lineno += 1 return self.docstring class NumpyDocstringParser(Parser): ... class ReStructuredParser(Parser): ... def parse(docstring: str, parser: str = "google", indent: int = 4) -> Docstring: if parser == "google": return GoogleDocstringParser(docstring, indent).parse() else: raise ValueError(f"Unknown parser: {parser}")