From dcad749ab06255edd1e9a04a0742272ddefd3179 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jind=C5=99ich=20B=C3=A4r?= Date: Wed, 8 Jan 2025 11:19:18 +0100 Subject: [PATCH] fix: respect indentation in multiline Python comments (#37) Fixes cases when the docstring parser parses: ``` Args: first_param: has a multiline comment with a colon in the wrong: place ``` as `{ first_param: "has a multiline comment with a colon in the", wrong: "place" }`. --- packages/plugin/package.json | 2 +- .../docspec-gen/google_docstring_processor.py | 27 +++++++++++++------ playground/python/src/__init__.py | 22 +++++++++++++-- 3 files changed, 40 insertions(+), 11 deletions(-) diff --git a/packages/plugin/package.json b/packages/plugin/package.json index 4b076c6..a64522a 100644 --- a/packages/plugin/package.json +++ b/packages/plugin/package.json @@ -1,6 +1,6 @@ { "name": "@apify/docusaurus-plugin-typedoc-api", - "version": "4.3.5", + "version": "4.3.6", "description": "Docusaurus plugin that provides source code API documentation powered by TypeDoc. ", "keywords": [ "docusaurus", diff --git a/packages/plugin/python-scripts/docspec-gen/google_docstring_processor.py b/packages/plugin/python-scripts/docspec-gen/google_docstring_processor.py index 154462c..3073bbd 100644 --- a/packages/plugin/python-scripts/docspec-gen/google_docstring_processor.py +++ b/packages/plugin/python-scripts/docspec-gen/google_docstring_processor.py @@ -121,6 +121,9 @@ def check_docstring_format(self, docstring: str) -> bool: def process(self, modules: t.List[docspec.Module], resolver: t.Optional[Resolver]) -> None: docspec.visit(modules, self._process) + def get_indent_size(self, line: str) -> int: + return len(line) - len(line.lstrip()) + def _process(self, node: docspec.ApiObject): if not node.docstring: return @@ -131,6 +134,7 @@ def _process(self, node: docspec.ApiObject): in_codeblock = False keyword = None multiline_argument_offset = -1 + state = { 'param_indent': None } def _commit(): if keyword: @@ -139,6 +143,13 @@ def _commit(): lines.extend(current_lines) current_lines.clear() + def is_continuation(line: str) -> bool: + if state.get('param_indent') is None: + state['param_indent'] = self.get_indent_size(line) + return False + + return self.get_indent_size(line) > state.get('param_indent') + for line in node.docstring.content.split("\n"): multiline_argument_offset += 1 if line.lstrip().startswith("```"): @@ -152,29 +163,29 @@ def _commit(): current_lines.append(line) continue - line = line.strip() - if line in self._keywords_map: + stripped = line.strip() + if stripped in self._keywords_map: _commit() - keyword = self._keywords_map[line] + keyword = self._keywords_map[stripped] continue if keyword is None: - lines.append(line) + lines.append(stripped) continue for param_re in self._param_res: - param_match = param_re.match(line) - if param_match: + param_match = param_re.match(stripped) + if param_match and not is_continuation(line): current_lines.append(param_match.groupdict()) multiline_argument_offset = 0 break if not param_match: if multiline_argument_offset == 1: - current_lines[-1]["desc"] += "\n" + line + current_lines[-1]["desc"] += "\n" + stripped multiline_argument_offset = 0 else: - current_lines.append(line) + current_lines.append(stripped) _commit() node.docstring.content = json.dumps({ diff --git a/playground/python/src/__init__.py b/playground/python/src/__init__.py index a15ae41..34eb71d 100644 --- a/playground/python/src/__init__.py +++ b/playground/python/src/__init__.py @@ -13,11 +13,29 @@ def __init__(self): """ print("Bar") - def foo(self) -> Foo: + def foo(self, count: int) -> Foo: """ The foo method of the bar class, prints "foo". + + Args: + count: The number of times to print "foo". + This comment is multiline, and contains + some urls too, look: https://apify.com + """ + print("foo " * count) + + def foo2(self, count: int, second_arg: str) -> Foo: + """ + The foo2 method of the bar class, prints "foo2". + + Args: + count: The number of times to print "foo2". + This comment is multiline, and contains some urls too, + look: https://apify.com + second_arg: The second argument. This shouldn't be a part of the previous argument's + description: even with a colon. """ - print("foo") + print("foo2 " * count) @docs_group('Classes') class BarBar(Bar):