From 2905c10d4e382dde966211d57ec769b3f2c2303a Mon Sep 17 00:00:00 2001 From: Daniel Goldman <danielgoldman4@gmail.com> Date: Sun, 30 Jun 2024 15:39:30 -0400 Subject: [PATCH 1/5] add failing test --- .../string_files/do_format_docstrings.toml | 15 +++++++++++++ tests/formatter/test_do_format_docstring.py | 22 +++++++++++++++++++ 2 files changed, 37 insertions(+) diff --git a/tests/_data/string_files/do_format_docstrings.toml b/tests/_data/string_files/do_format_docstrings.toml index d8d29d9..da48739 100644 --- a/tests/_data/string_files/do_format_docstrings.toml +++ b/tests/_data/string_files/do_format_docstrings.toml @@ -213,3 +213,18 @@ instring='''""" eBay kinda suss """''' outstring='''"""eBay kinda suss."""''' + +[issue_263] +# the `xx.\n\n` ensures there are a summary and a description sections +# the `:param a:` creates a field +# the `b`s create text that is long enough to trigger a line wrap without being so long that they count as code +# the `s3://cccc.` is a url +instring='''"""xx. + + :param a: bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb s3://cccc. +"""''' +outstring='''"""xx. + + :param a: bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb + s3://cccc. + """''' \ No newline at end of file diff --git a/tests/formatter/test_do_format_docstring.py b/tests/formatter/test_do_format_docstring.py index 18b65d7..1f79932 100644 --- a/tests/formatter/test_do_format_docstring.py +++ b/tests/formatter/test_do_format_docstring.py @@ -337,3 +337,25 @@ def test_format_docstring_with_non_cap_words(self, test_args, args): INDENTATION, instring, ) + + @pytest.mark.unit + @pytest.mark.parametrize("args", [[""]]) + def test_idk(self, test_args, args): + """Do not double-process urls in fields + + See issue #263 + """ + uut = Formatter( + test_args, + sys.stderr, + sys.stdin, + sys.stdout, + ) + + instring = self.TEST_STRINGS["issue_263"]["instring"] + outstring = self.TEST_STRINGS["issue_263"]["outstring"] + + assert outstring == uut._do_format_docstring( + INDENTATION, + instring, + ) From 041902f8d06bac4257bdfe350136cd573107facd Mon Sep 17 00:00:00 2001 From: Daniel Goldman <danielgoldman4@gmail.com> Date: Sun, 30 Jun 2024 15:48:52 -0400 Subject: [PATCH 2/5] assume that all urls after first field are in field list --- src/docformatter/syntax.py | 18 ++++++++---------- 1 file changed, 8 insertions(+), 10 deletions(-) diff --git a/src/docformatter/syntax.py b/src/docformatter/syntax.py index a389341..5e40dea 100644 --- a/src/docformatter/syntax.py +++ b/src/docformatter/syntax.py @@ -950,7 +950,7 @@ def _field_over_url( field_idx: List[Tuple[int, int]], url_idx: List[Tuple[int, int]], ): - """Remove URL indices that overlap with filed list indices. + """Remove URL indices that overlap with field list indices. Parameters ---------- @@ -965,14 +965,12 @@ def _field_over_url( The url_idx list with any tuples that have indices overlapping with field list indices removed. """ - for _fieldl, _fieldu in field_idx: - for _key, _value in enumerate(url_idx): - if ( - _value[0] == _fieldl - or _value[0] == _fieldu - or _value[1] == _fieldl - or _value[1] == _fieldu - ): - url_idx.pop(_key) + if not field_idx: + return url_idx + any_param_start = min(e[0] for e in field_idx) + for _key, _value in enumerate(url_idx): + if _value[0] > any_param_start: + url_idx.pop(_key) return url_idx + From 434fd5e86968b9d3ebf3f167c9b5eb07bcd80bca Mon Sep 17 00:00:00 2001 From: Daniel Goldman <danielgoldman4@gmail.com> Date: Sun, 30 Jun 2024 15:50:09 -0400 Subject: [PATCH 3/5] fix modifying iterated collection causing skips --- src/docformatter/syntax.py | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/src/docformatter/syntax.py b/src/docformatter/syntax.py index 5e40dea..f375172 100644 --- a/src/docformatter/syntax.py +++ b/src/docformatter/syntax.py @@ -968,9 +968,11 @@ def _field_over_url( if not field_idx: return url_idx + nonoverlapping_urls = [] + any_param_start = min(e[0] for e in field_idx) for _key, _value in enumerate(url_idx): - if _value[0] > any_param_start: - url_idx.pop(_key) - return url_idx + if _value[1] < any_param_start: + nonoverlapping_urls.append(_value) + return nonoverlapping_urls From 483b31e66818fa8040f5893f02873c0ba9f53a54 Mon Sep 17 00:00:00 2001 From: Daniel Goldman <danielgoldman4@gmail.com> Date: Sun, 30 Jun 2024 16:20:47 -0400 Subject: [PATCH 4/5] add test for epytext style too --- .../_data/string_files/do_format_docstrings.toml | 13 ++++++++++++- tests/formatter/test_do_format_docstring.py | 15 +++++++-------- 2 files changed, 19 insertions(+), 9 deletions(-) diff --git a/tests/_data/string_files/do_format_docstrings.toml b/tests/_data/string_files/do_format_docstrings.toml index da48739..5cc1735 100644 --- a/tests/_data/string_files/do_format_docstrings.toml +++ b/tests/_data/string_files/do_format_docstrings.toml @@ -215,6 +215,7 @@ eBay kinda suss outstring='''"""eBay kinda suss."""''' [issue_263] +[issue_263.sphinx] # the `xx.\n\n` ensures there are a summary and a description sections # the `:param a:` creates a field # the `b`s create text that is long enough to trigger a line wrap without being so long that they count as code @@ -227,4 +228,14 @@ outstring='''"""xx. :param a: bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb s3://cccc. - """''' \ No newline at end of file + """''' +[issue_263.epytext] +instring='''"""xx. + + @param a: bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb s3://cccc. + """''' +outstring='''"""xx. + + @param a: bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb + s3://cccc. + """''' diff --git a/tests/formatter/test_do_format_docstring.py b/tests/formatter/test_do_format_docstring.py index 1f79932..5bf544b 100644 --- a/tests/formatter/test_do_format_docstring.py +++ b/tests/formatter/test_do_format_docstring.py @@ -339,12 +339,14 @@ def test_format_docstring_with_non_cap_words(self, test_args, args): ) @pytest.mark.unit - @pytest.mark.parametrize("args", [[""]]) - def test_idk(self, test_args, args): + @pytest.mark.parametrize("args", [["--style", "sphinx", ""], ["--style", "epytext", ""]]) + def test_do_not_double_process_urls(self, test_args, args): """Do not double-process urls in fields See issue #263 """ + style = args[1] + uut = Formatter( test_args, sys.stderr, @@ -352,10 +354,7 @@ def test_idk(self, test_args, args): sys.stdout, ) - instring = self.TEST_STRINGS["issue_263"]["instring"] - outstring = self.TEST_STRINGS["issue_263"]["outstring"] + instring = self.TEST_STRINGS["issue_263"][style]["instring"] + outstring = self.TEST_STRINGS["issue_263"][style]["outstring"] - assert outstring == uut._do_format_docstring( - INDENTATION, - instring, - ) + assert outstring == uut._do_format_docstring(INDENTATION, instring, ) From 7dcd041d49e5f54e9f3d0c099ae3179110648538 Mon Sep 17 00:00:00 2001 From: Daniel Goldman <danielgoldman4@gmail.com> Date: Sun, 30 Jun 2024 16:57:28 -0400 Subject: [PATCH 5/5] add some unit tests for various URL scenarios --- tests/test_syntax_functions.py | 75 ++++++++++++++++++++++++++++++++++ 1 file changed, 75 insertions(+) diff --git a/tests/test_syntax_functions.py b/tests/test_syntax_functions.py index 235bb45..24d45a9 100644 --- a/tests/test_syntax_functions.py +++ b/tests/test_syntax_functions.py @@ -34,12 +34,14 @@ do_find_links() do_skip_link() """ +import textwrap # Third Party Imports import pytest # docformatter Package Imports import docformatter +from docformatter import do_split_description class TestURLHandlers: @@ -159,3 +161,76 @@ def test_find_double_backtick_directives(self): " Since a mail could be ``Cc``'d to two lists with different ``Reply-To`` munging" "options set." ) + + +class TestSplitDescription: + """Class for testing the function to process the description + + Includes tests for: + - do_split_description() + + """ + med_str = "m"*40 # long enough that 2 won't fit on a line + indent = " " + + def do_test(self, text): + return do_split_description(textwrap.dedent(text), self.indent, 72, "sphinx") + + def indent_all(self, strs): + return [self.indent + s for s in strs] + + @pytest.mark.unit + def test_split_description_url_outside_param(self): + assert self.do_test( + f"""\ + {self.med_str} https://{self.med_str} + :param a: {self.med_str} + """ + ) == self.indent_all([ + self.med_str, + f"https://{self.med_str}", + f":param a: {self.med_str}", + ]) + + @pytest.mark.unit + def test_split_description_single_url_in_param(self): + assert self.do_test( + f"""\ + {self.med_str} + :param a: {self.med_str} https://{self.med_str}a + """ + ) == self.indent_all([ + self.med_str, + f":param a: {self.med_str}", + self.indent + f"https://{self.med_str}a", + ]) + + @pytest.mark.unit + def test_split_description_single_url_in_multiple_params(self): + assert self.do_test( + f"""\ + {self.med_str} + :param a: {self.med_str} https://{self.med_str}a + :param b: {self.med_str} https://{self.med_str}b + """ + ) == self.indent_all([ + self.med_str, + f":param a: {self.med_str}", + self.indent + f"https://{self.med_str}a", + f":param b: {self.med_str}", + self.indent + f"https://{self.med_str}b", + ]) + + @pytest.mark.unit + def test_split_description_multiple_urls_in_param(self): + assert self.do_test( + f"""\ + {self.med_str} + :param a: {self.med_str} https://{self.med_str}0 https://{self.med_str}1 + """ + ) == self.indent_all([ + self.med_str, + f":param a: {self.med_str}", + self.indent + f"https://{self.med_str}0", + self.indent + f"https://{self.med_str}1", + ])