def __init__(self, docstring): # type: (Text) -> None docstring = self._cleanup(docstring) docstring = IndentTrimmer.trim_empty_lines(docstring) docstring = IndentTrimmer.trim_text(docstring) lines = docstring.split("\n") self._lines = IndentTrimmer.trim_lines(lines)
def test_trim_empty_lines(self): self.assertEqual( IndentTrimmer.trim_empty_lines("\n \n test\ntest2\n \n "), " test\ntest2") self.assertEqual(IndentTrimmer.trim_empty_lines("\n \n\n "), "") self.assertEqual(IndentTrimmer.trim_empty_lines("\n \n test \n "), " test ")
def test_trim_text(self): self.assertEqual(IndentTrimmer.trim_text(" asd\n asd\n asd\n"), " asd\nasd\n asd\n") self.assertEqual(IndentTrimmer.trim_text(" asd\nasd\n asd\n"), " asd\nasd\n asd\n") self.assertEqual(IndentTrimmer.trim_text(" asd\n asd\n asd\n"), "asd\nasd\n asd\n")
def test_trim_lines(self): self.assertEqual( IndentTrimmer.trim_lines([" asd", " asd", " asd"]), [" asd", "asd", " asd"], ) self.assertEqual( IndentTrimmer.trim_lines([" asd", " asd", "", " asd"]), [" asd", "asd", "", " asd"], ) self.assertEqual( IndentTrimmer.trim_lines([" asd", "asd", " asd", ""]), [" asd", "asd", " asd", ""], ) self.assertEqual(IndentTrimmer.trim_lines([]), [])
def _get_function_def_lines(self, function_record): # type: (FunctionRecord) -> List[Text] """ Get all function definition lines for comment type hints lookup. Removes indentation. Arguments: function_record -- Function record for source lookup. Returns: Function definition lines as an array. """ if not isinstance(function_record.node, (ast.AsyncFunctionDef, ast.FunctionDef)): raise TypeError result = [] # type: List[Text] start_index = function_record.line_number - 1 end_index = function_record.node.body[0].lineno - 1 result = self.source_lines[start_index:end_index] result = [i.rstrip("\n") for i in result] result = IndentTrimmer.trim_lines(result) return result
def add_line_indent(self, section_name, line): # type: (Text, Text) -> None """ Add line respecting indent of the current section block. Arguments: section_name -- Target section title line -- Line to add """ if section_name in self: section = self[section_name] if section.blocks and section.blocks[-1].lines: indent = IndentTrimmer.get_line_indent( section.blocks[-1].lines[-1]) line = IndentTrimmer.indent_line(line, indent) self.add_line(section_name, line)
def render(self): # type: () -> Text """ Render trimmed block lines. Returns: Block lines as a text. """ lines = IndentTrimmer.trim_lines(self.lines) return "\n".join(lines)
def build_sections(self, content): # type: (Text) -> SectionMap """ Parse docstring and split it to sections with arrays of strings. Arguments: content -- Object docstring. Returns: A dictionary where key is a section name and value is a list of string sof this section. """ self._reset() for line in content.split("\n"): self._current_indent = IndentTrimmer.get_line_indent(line) line = line.strip() # adding new lines to a doctest code block if self._in_doctest_block: self._parse_doctest_line(line) continue # adding new lines to a tilde block if self._in_tilde_block: self._parse_tilde_block_line(line) continue # adding new lines to a code block if self._in_md_codeblock: self._parse_md_codeblock_line(line) continue # adding new lines to an indented code block if self._in_indent_codeblock: self._parse_indent_codeblock_line(line) continue # adding new block on empty line outside of a code block if not line: self._add_block() continue self._parse_line(line) if self._in_indent_codeblock: self._trim_empty_lines() self._add_line("```", indent=0) return self.section_map
def get_toc_line(cls, line, level=0): # type: (Text, int) -> Text """ Get ToC `line` of given `level`. Arguments: line -- Line to prepare. level -- Line level, starts with `0`. Returns: Ready to insert ToC line. """ indent = cls.TOC_INDENT * level return IndentTrimmer.indent_line("- {}".format(line), indent)
def _cleanup(docstring): # type: (Text) -> Text """ Fix multiline docstrings starting with no newline after quotes. Arguments: docstring -- Raw docstring. Returns: Aligned docstring. """ if "\n" in docstring and docstring[0] != "\n": lines = docstring.split("\n") next_line_index = 1 next_line = lines[next_line_index] while not next_line.strip() and next_line_index < len(lines) - 1: next_line_index += 1 next_line = lines[next_line_index] indent = IndentTrimmer.get_line_indent(next_line) docstring = "\n{}{}".format(" " * indent, docstring) return IndentTrimmer.trim_text(docstring)
def append(self, content): # type: (Text) -> None """ Append `content` to the document. Handle trimming and sectioning the content and update `title` and `toc_section` fields. Arguments: content -- Text to add. """ content = IndentTrimmer.trim_empty_lines(content) if not content: return if not self.subtitle and not self.sections and not content.startswith( "#"): self.subtitle = content else: self._sections.append(content) self._content = self._build_content()
def read(self, source_path=None): # type: (Optional[Path]) -> None """ Read and parse content from `source_path`. Arguments: source_path -- Input file path. If not provided - `path` is used. """ path = source_path or self._path self._content = path.read_text(encoding="utf-8") self._title = "" self._toc_section = "" title, content = extract_md_title(self._content) if title: self._title = title sections = content.split(self._section_separator) self._sections = [] for section in sections: section = IndentTrimmer.trim_empty_lines(section) if not section: continue if self.is_toc(section) and not self._toc_section: self._toc_section = section if self._sections: self._subtitle = self._section_separator.join( self._sections) self._sections = [] continue self._sections.append(section) # extract subtitle from the first section if it is not a title if (not self._subtitle and self._sections and not self._sections[0].startswith("#")): self._subtitle = self._sections.pop(0)
def test_trim_line(self): self.assertEqual(IndentTrimmer.trim_line(" test", 2), " test") self.assertEqual(IndentTrimmer.trim_line(" test", 2), "test") self.assertEqual(IndentTrimmer.trim_line("test", 2), "test") self.assertEqual(IndentTrimmer.trim_line(" ", 2), " ")
def test_get_line_indent(self): self.assertEqual(IndentTrimmer.get_line_indent(" test"), 3) self.assertEqual(IndentTrimmer.get_line_indent("test"), 0) self.assertEqual(IndentTrimmer.get_line_indent(" "), 2) self.assertEqual(IndentTrimmer.get_line_indent(""), 0)