From 7040ca3bbd7b311a9b4ecda82b11a43e5d3856b0 Mon Sep 17 00:00:00 2001 From: James Braza Date: Mon, 21 Jul 2025 11:22:39 -0700 Subject: [PATCH 1/2] Allowing union None support in parsing, with tests --- docstring_parser/epydoc.py | 2 +- docstring_parser/google.py | 4 ++-- docstring_parser/numpydoc.py | 4 ++-- docstring_parser/parser.py | 4 +++- docstring_parser/rest.py | 2 +- docstring_parser/tests/test_epydoc.py | 3 ++- docstring_parser/tests/test_google.py | 3 ++- docstring_parser/tests/test_numpydoc.py | 3 ++- docstring_parser/tests/test_parser.py | 20 ++++++++++++++++++++ docstring_parser/tests/test_rest.py | 3 ++- 10 files changed, 37 insertions(+), 11 deletions(-) diff --git a/docstring_parser/epydoc.py b/docstring_parser/epydoc.py index 4d4dde6..64b59e1 100644 --- a/docstring_parser/epydoc.py +++ b/docstring_parser/epydoc.py @@ -26,7 +26,7 @@ def _clean_str(string: str) -> T.Optional[str]: return None -def parse(text: str) -> Docstring: +def parse(text: str | None) -> Docstring: """Parse the epydoc-style docstring into its components. :returns: parsed docstring diff --git a/docstring_parser/google.py b/docstring_parser/google.py index aa4284e..c7910b6 100644 --- a/docstring_parser/google.py +++ b/docstring_parser/google.py @@ -202,7 +202,7 @@ def add_section(self, section: Section): self.sections[section.title] = section self._setup() - def parse(self, text: str) -> Docstring: + def parse(self, text: str | None) -> Docstring: """Parse the Google-style docstring into its components. :returns: parsed docstring @@ -293,7 +293,7 @@ def parse(self, text: str) -> Docstring: return ret -def parse(text: str) -> Docstring: +def parse(text: str | None) -> Docstring: """Parse the Google-style docstring into its components. :returns: parsed docstring diff --git a/docstring_parser/numpydoc.py b/docstring_parser/numpydoc.py index 836e776..b83b983 100644 --- a/docstring_parser/numpydoc.py +++ b/docstring_parser/numpydoc.py @@ -325,7 +325,7 @@ def add_section(self, section: Section): self.sections[section.title] = section self._setup() - def parse(self, text: str) -> Docstring: + def parse(self, text: str | None) -> Docstring: """Parse the numpy-style docstring into its components. :returns: parsed docstring @@ -370,7 +370,7 @@ def parse(self, text: str) -> Docstring: return ret -def parse(text: str) -> Docstring: +def parse(text: str | None) -> Docstring: """Parse the numpy-style docstring into its components. :returns: parsed docstring diff --git a/docstring_parser/parser.py b/docstring_parser/parser.py index 2710e63..ed1f59c 100644 --- a/docstring_parser/parser.py +++ b/docstring_parser/parser.py @@ -20,7 +20,9 @@ } -def parse(text: str, style: DocstringStyle = DocstringStyle.AUTO) -> Docstring: +def parse( + text: str | None, style: DocstringStyle = DocstringStyle.AUTO +) -> Docstring: """Parse the docstring into its components. :param text: docstring text to parse diff --git a/docstring_parser/rest.py b/docstring_parser/rest.py index b707df8..9a7edcf 100644 --- a/docstring_parser/rest.py +++ b/docstring_parser/rest.py @@ -99,7 +99,7 @@ def _build_meta(args: T.List[str], desc: str) -> DocstringMeta: return DocstringMeta(args=args, description=desc) -def parse(text: str) -> Docstring: +def parse(text: str | None) -> Docstring: """Parse the ReST-style docstring into its components. :returns: parsed docstring diff --git a/docstring_parser/tests/test_epydoc.py b/docstring_parser/tests/test_epydoc.py index 965b440..f968593 100644 --- a/docstring_parser/tests/test_epydoc.py +++ b/docstring_parser/tests/test_epydoc.py @@ -10,6 +10,7 @@ @pytest.mark.parametrize( "source, expected", [ + pytest.param(None, None, id="No __doc__"), ("", None), ("\n", None), ("Short description", "Short description"), @@ -17,7 +18,7 @@ ("\n Short description\n", "Short description"), ], ) -def test_short_description(source: str, expected: str) -> None: +def test_short_description(source: str | None, expected: str | None) -> None: """Test parsing short description.""" docstring = parse(source) assert docstring.short_description == expected diff --git a/docstring_parser/tests/test_google.py b/docstring_parser/tests/test_google.py index b32c04e..505cd10 100644 --- a/docstring_parser/tests/test_google.py +++ b/docstring_parser/tests/test_google.py @@ -143,6 +143,7 @@ def test_google_parser_custom_sections_after() -> None: @pytest.mark.parametrize( "source, expected", [ + pytest.param(None, None, id="No __doc__"), ("", None), ("\n", None), ("Short description", "Short description"), @@ -150,7 +151,7 @@ def test_google_parser_custom_sections_after() -> None: ("\n Short description\n", "Short description"), ], ) -def test_short_description(source: str, expected: str) -> None: +def test_short_description(source: str | None, expected: str | None) -> None: """Test parsing short description.""" docstring = parse(source) assert docstring.short_description == expected diff --git a/docstring_parser/tests/test_numpydoc.py b/docstring_parser/tests/test_numpydoc.py index 2394c61..867c235 100644 --- a/docstring_parser/tests/test_numpydoc.py +++ b/docstring_parser/tests/test_numpydoc.py @@ -9,6 +9,7 @@ @pytest.mark.parametrize( "source, expected", [ + pytest.param(None, None, id="No __doc__"), ("", None), ("\n", None), ("Short description", "Short description"), @@ -16,7 +17,7 @@ ("\n Short description\n", "Short description"), ], ) -def test_short_description(source: str, expected: str) -> None: +def test_short_description(source: str | None, expected: str | None) -> None: """Test parsing short description.""" docstring = parse(source) assert docstring.short_description == expected diff --git a/docstring_parser/tests/test_parser.py b/docstring_parser/tests/test_parser.py index 73b8c9c..d97d4e7 100644 --- a/docstring_parser/tests/test_parser.py +++ b/docstring_parser/tests/test_parser.py @@ -5,6 +5,26 @@ from docstring_parser.parser import parse +@pytest.mark.parametrize( + "source, expected", + [ + pytest.param(None, None, id="No __doc__"), + ("", None), + ("\n", None), + ("Short description", "Short description"), + ("\nShort description\n", "Short description"), + ("\n Short description\n", "Short description"), + ], +) +def test_short_description(source: str | None, expected: str | None) -> None: + """Test parsing short description.""" + docstring = parse(source) + assert docstring.short_description == expected + assert docstring.description == expected + assert docstring.long_description is None + assert not docstring.meta + + def test_rest() -> None: """Test ReST-style parser autodetection.""" docstring = parse( diff --git a/docstring_parser/tests/test_rest.py b/docstring_parser/tests/test_rest.py index 411c277..6ca5a3c 100644 --- a/docstring_parser/tests/test_rest.py +++ b/docstring_parser/tests/test_rest.py @@ -10,6 +10,7 @@ @pytest.mark.parametrize( "source, expected", [ + pytest.param(None, None, id="No __doc__"), ("", None), ("\n", None), ("Short description", "Short description"), @@ -17,7 +18,7 @@ ("\n Short description\n", "Short description"), ], ) -def test_short_description(source: str, expected: str) -> None: +def test_short_description(source: str | None, expected: str | None) -> None: """Test parsing short description.""" docstring = parse(source) assert docstring.short_description == expected From aec2b1d0e7ee7b5fa5c1e8f594410f2a335d9f96 Mon Sep 17 00:00:00 2001 From: James Braza Date: Thu, 24 Jul 2025 23:19:26 -0700 Subject: [PATCH 2/2] Moved from union syntax to typing.Optional --- docstring_parser/epydoc.py | 2 +- docstring_parser/google.py | 4 ++-- docstring_parser/numpydoc.py | 4 ++-- docstring_parser/parser.py | 2 +- docstring_parser/rest.py | 2 +- docstring_parser/tests/test_epydoc.py | 4 +++- docstring_parser/tests/test_google.py | 4 +++- docstring_parser/tests/test_numpydoc.py | 4 +++- docstring_parser/tests/test_parser.py | 6 +++++- docstring_parser/tests/test_rest.py | 4 +++- 10 files changed, 24 insertions(+), 12 deletions(-) diff --git a/docstring_parser/epydoc.py b/docstring_parser/epydoc.py index 64b59e1..96c9726 100644 --- a/docstring_parser/epydoc.py +++ b/docstring_parser/epydoc.py @@ -26,7 +26,7 @@ def _clean_str(string: str) -> T.Optional[str]: return None -def parse(text: str | None) -> Docstring: +def parse(text: T.Optional[str]) -> Docstring: """Parse the epydoc-style docstring into its components. :returns: parsed docstring diff --git a/docstring_parser/google.py b/docstring_parser/google.py index c7910b6..244e698 100644 --- a/docstring_parser/google.py +++ b/docstring_parser/google.py @@ -202,7 +202,7 @@ def add_section(self, section: Section): self.sections[section.title] = section self._setup() - def parse(self, text: str | None) -> Docstring: + def parse(self, text: T.Optional[str]) -> Docstring: """Parse the Google-style docstring into its components. :returns: parsed docstring @@ -293,7 +293,7 @@ def parse(self, text: str | None) -> Docstring: return ret -def parse(text: str | None) -> Docstring: +def parse(text: T.Optional[str]) -> Docstring: """Parse the Google-style docstring into its components. :returns: parsed docstring diff --git a/docstring_parser/numpydoc.py b/docstring_parser/numpydoc.py index b83b983..eca5233 100644 --- a/docstring_parser/numpydoc.py +++ b/docstring_parser/numpydoc.py @@ -325,7 +325,7 @@ def add_section(self, section: Section): self.sections[section.title] = section self._setup() - def parse(self, text: str | None) -> Docstring: + def parse(self, text: T.Optional[str]) -> Docstring: """Parse the numpy-style docstring into its components. :returns: parsed docstring @@ -370,7 +370,7 @@ def parse(self, text: str | None) -> Docstring: return ret -def parse(text: str | None) -> Docstring: +def parse(text: T.Optional[str]) -> Docstring: """Parse the numpy-style docstring into its components. :returns: parsed docstring diff --git a/docstring_parser/parser.py b/docstring_parser/parser.py index ed1f59c..c769a1f 100644 --- a/docstring_parser/parser.py +++ b/docstring_parser/parser.py @@ -21,7 +21,7 @@ def parse( - text: str | None, style: DocstringStyle = DocstringStyle.AUTO + text: T.Optional[str], style: DocstringStyle = DocstringStyle.AUTO ) -> Docstring: """Parse the docstring into its components. diff --git a/docstring_parser/rest.py b/docstring_parser/rest.py index 9a7edcf..772cf2f 100644 --- a/docstring_parser/rest.py +++ b/docstring_parser/rest.py @@ -99,7 +99,7 @@ def _build_meta(args: T.List[str], desc: str) -> DocstringMeta: return DocstringMeta(args=args, description=desc) -def parse(text: str | None) -> Docstring: +def parse(text: T.Optional[str]) -> Docstring: """Parse the ReST-style docstring into its components. :returns: parsed docstring diff --git a/docstring_parser/tests/test_epydoc.py b/docstring_parser/tests/test_epydoc.py index f968593..e9821dc 100644 --- a/docstring_parser/tests/test_epydoc.py +++ b/docstring_parser/tests/test_epydoc.py @@ -18,7 +18,9 @@ ("\n Short description\n", "Short description"), ], ) -def test_short_description(source: str | None, expected: str | None) -> None: +def test_short_description( + source: T.Optional[str], expected: T.Optional[str] +) -> None: """Test parsing short description.""" docstring = parse(source) assert docstring.short_description == expected diff --git a/docstring_parser/tests/test_google.py b/docstring_parser/tests/test_google.py index 505cd10..5a3570a 100644 --- a/docstring_parser/tests/test_google.py +++ b/docstring_parser/tests/test_google.py @@ -151,7 +151,9 @@ def test_google_parser_custom_sections_after() -> None: ("\n Short description\n", "Short description"), ], ) -def test_short_description(source: str | None, expected: str | None) -> None: +def test_short_description( + source: T.Optional[str], expected: T.Optional[str] +) -> None: """Test parsing short description.""" docstring = parse(source) assert docstring.short_description == expected diff --git a/docstring_parser/tests/test_numpydoc.py b/docstring_parser/tests/test_numpydoc.py index 867c235..2f2ef42 100644 --- a/docstring_parser/tests/test_numpydoc.py +++ b/docstring_parser/tests/test_numpydoc.py @@ -17,7 +17,9 @@ ("\n Short description\n", "Short description"), ], ) -def test_short_description(source: str | None, expected: str | None) -> None: +def test_short_description( + source: T.Optional[str], expected: T.Optional[str] +) -> None: """Test parsing short description.""" docstring = parse(source) assert docstring.short_description == expected diff --git a/docstring_parser/tests/test_parser.py b/docstring_parser/tests/test_parser.py index d97d4e7..e624976 100644 --- a/docstring_parser/tests/test_parser.py +++ b/docstring_parser/tests/test_parser.py @@ -1,5 +1,7 @@ """Tests for generic docstring routines.""" +import typing as T + import pytest from docstring_parser.common import DocstringStyle, ParseError from docstring_parser.parser import parse @@ -16,7 +18,9 @@ ("\n Short description\n", "Short description"), ], ) -def test_short_description(source: str | None, expected: str | None) -> None: +def test_short_description( + source: T.Optional[str], expected: T.Optional[str] +) -> None: """Test parsing short description.""" docstring = parse(source) assert docstring.short_description == expected diff --git a/docstring_parser/tests/test_rest.py b/docstring_parser/tests/test_rest.py index 6ca5a3c..19ba3d8 100644 --- a/docstring_parser/tests/test_rest.py +++ b/docstring_parser/tests/test_rest.py @@ -18,7 +18,9 @@ ("\n Short description\n", "Short description"), ], ) -def test_short_description(source: str | None, expected: str | None) -> None: +def test_short_description( + source: T.Optional[str], expected: T.Optional[str] +) -> None: """Test parsing short description.""" docstring = parse(source) assert docstring.short_description == expected