From 29d243911f17a19f445e6425089972c8f3a56bab Mon Sep 17 00:00:00 2001 From: Kevin Smith Date: Wed, 30 Jul 2025 11:27:49 -0500 Subject: [PATCH 1/3] Fix numpydoc example parsing --- docstring_parser/common.py | 8 +++++++- docstring_parser/numpydoc.py | 38 +++++++++++++++++++++++++++++------- 2 files changed, 38 insertions(+), 8 deletions(-) diff --git a/docstring_parser/common.py b/docstring_parser/common.py index 880e378..389ac50 100644 --- a/docstring_parser/common.py +++ b/docstring_parser/common.py @@ -51,7 +51,10 @@ class DocstringMeta: """ def __init__( - self, args: T.List[str], description: T.Optional[str] + self, + args: T.List[str], + description: T.Optional[str], + post_description: T.Optional[str], ) -> None: """Initialize self. @@ -59,9 +62,12 @@ def __init__( dependent on the kind of docstring; it's used to distinguish between custom docstring meta information items. :param description: associated docstring description. + :param post_description: additional docstring description that + may appear after other relevant content. """ self.args = args self.description = description + self.post_description = post_description class DocstringParam(DocstringMeta): diff --git a/docstring_parser/numpydoc.py b/docstring_parser/numpydoc.py index eca5233..c13a6d4 100644 --- a/docstring_parser/numpydoc.py +++ b/docstring_parser/numpydoc.py @@ -244,22 +244,46 @@ def parse(self, text: str) -> T.Iterable[DocstringMeta]: :param text: section body text. Should be cleaned with ``inspect.cleandoc`` before parsing. """ - lines = dedent(text).strip().splitlines() + lines = [x.rstrip() for x in dedent(text).strip().splitlines()] while lines: snippet_lines = [] description_lines = [] + post_description_lines = [] + + # Parse description of snippet while lines: - if not lines[0].startswith(">>>"): + if lines[0].startswith(">>>"): + break + description_lines.append(lines.pop(0)) + + # Parse code of snippet + while lines: + if not lines[0].startswith(">>>") and not lines[0].startswith('...'): break snippet_lines.append(lines.pop(0)) + + # Parse output of snippet while lines: - if lines[0].startswith(">>>"): + # Bail out at blank lines + if not lines[0]: + lines.pop(0) break - description_lines.append(lines.pop(0)) - yield DocstringExample( + # Bail out if a new snippet is started + elif lines[0].startswith(">>>"): + break + else: + snippet_lines.append(lines.pop(0)) + + # if there is following text, but no more snippets, make this a post description. + if not [x for x in lines if '>>>' in x]: + post_description_lines.extend(lines) + lines = [] + + yield dict( [self.key], - snippet="\n".join(snippet_lines) if snippet_lines else None, - description="\n".join(description_lines), + snippet="\n".join(snippet_lines).strip() if snippet_lines else None, + description="\n".join(description_lines).strip(), + post_description="\n".join(post_description_lines).strip(), ) From 8d1e6e009761813772aaea7e7fa65553419feec1 Mon Sep 17 00:00:00 2001 From: Kevin Smith Date: Wed, 30 Jul 2025 11:32:40 -0500 Subject: [PATCH 2/3] Fix numpydoc example parsing --- docstring_parser/common.py | 8 +------- docstring_parser/numpydoc.py | 4 +--- 2 files changed, 2 insertions(+), 10 deletions(-) diff --git a/docstring_parser/common.py b/docstring_parser/common.py index 389ac50..c412cef 100644 --- a/docstring_parser/common.py +++ b/docstring_parser/common.py @@ -51,10 +51,7 @@ class DocstringMeta: """ def __init__( - self, - args: T.List[str], - description: T.Optional[str], - post_description: T.Optional[str], + self, args: T.List[str], description: T.Optional[str], ) -> None: """Initialize self. @@ -62,12 +59,9 @@ def __init__( dependent on the kind of docstring; it's used to distinguish between custom docstring meta information items. :param description: associated docstring description. - :param post_description: additional docstring description that - may appear after other relevant content. """ self.args = args self.description = description - self.post_description = post_description class DocstringParam(DocstringMeta): diff --git a/docstring_parser/numpydoc.py b/docstring_parser/numpydoc.py index c13a6d4..c8b315c 100644 --- a/docstring_parser/numpydoc.py +++ b/docstring_parser/numpydoc.py @@ -248,7 +248,6 @@ def parse(self, text: str) -> T.Iterable[DocstringMeta]: while lines: snippet_lines = [] description_lines = [] - post_description_lines = [] # Parse description of snippet while lines: @@ -276,14 +275,13 @@ def parse(self, text: str) -> T.Iterable[DocstringMeta]: # if there is following text, but no more snippets, make this a post description. if not [x for x in lines if '>>>' in x]: - post_description_lines.extend(lines) + description_lines.extend(lines) lines = [] yield dict( [self.key], snippet="\n".join(snippet_lines).strip() if snippet_lines else None, description="\n".join(description_lines).strip(), - post_description="\n".join(post_description_lines).strip(), ) From 689461a0786119784c0d1651ba19f432e1144565 Mon Sep 17 00:00:00 2001 From: Kevin Smith Date: Wed, 30 Jul 2025 11:45:24 -0500 Subject: [PATCH 3/3] Fix result type of numpy example --- docstring_parser/common.py | 2 ++ docstring_parser/numpydoc.py | 8 +++++--- 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/docstring_parser/common.py b/docstring_parser/common.py index c412cef..6c596f5 100644 --- a/docstring_parser/common.py +++ b/docstring_parser/common.py @@ -140,11 +140,13 @@ def __init__( args: T.List[str], snippet: T.Optional[str], description: T.Optional[str], + post_snippet: T.Optional[str] = None, ) -> None: """Initialize self.""" super().__init__(args, description) self.snippet = snippet self.description = description + self.post_snippet = post_snippet class Docstring: diff --git a/docstring_parser/numpydoc.py b/docstring_parser/numpydoc.py index c8b315c..f76e26a 100644 --- a/docstring_parser/numpydoc.py +++ b/docstring_parser/numpydoc.py @@ -238,7 +238,7 @@ class ExamplesSection(Section): [ 6586976, 22740995]]) """ - def parse(self, text: str) -> T.Iterable[DocstringMeta]: + def parse(self, text: str) -> T.Iterable[DocstringExample]: """Parse ``DocstringExample`` objects from the body of this section. :param text: section body text. Should be cleaned with @@ -248,6 +248,7 @@ def parse(self, text: str) -> T.Iterable[DocstringMeta]: while lines: snippet_lines = [] description_lines = [] + post_snippet_lines = [] # Parse description of snippet while lines: @@ -275,13 +276,14 @@ def parse(self, text: str) -> T.Iterable[DocstringMeta]: # if there is following text, but no more snippets, make this a post description. if not [x for x in lines if '>>>' in x]: - description_lines.extend(lines) + post_snippet_lines.extend(lines) lines = [] - yield dict( + yield DocstringExample( [self.key], snippet="\n".join(snippet_lines).strip() if snippet_lines else None, description="\n".join(description_lines).strip(), + post_snippet="\n".join(post_snippet_lines).strip(), )