Skip to content

Commit a850cf9

Browse files
authored
Do not double-process urls (#284)
* add failing test * assume that all urls after first field are in field list * fix modifying iterated collection causing skips * add test for epytext style too * add some unit tests for various URL scenarios
1 parent 504107b commit a850cf9

File tree

4 files changed

+134
-12
lines changed

4 files changed

+134
-12
lines changed

src/docformatter/syntax.py

Lines changed: 12 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -950,7 +950,7 @@ def _field_over_url(
950950
field_idx: List[Tuple[int, int]],
951951
url_idx: List[Tuple[int, int]],
952952
):
953-
"""Remove URL indices that overlap with filed list indices.
953+
"""Remove URL indices that overlap with field list indices.
954954
955955
Parameters
956956
----------
@@ -965,14 +965,14 @@ def _field_over_url(
965965
The url_idx list with any tuples that have indices overlapping with field
966966
list indices removed.
967967
"""
968-
for _fieldl, _fieldu in field_idx:
969-
for _key, _value in enumerate(url_idx):
970-
if (
971-
_value[0] == _fieldl
972-
or _value[0] == _fieldu
973-
or _value[1] == _fieldl
974-
or _value[1] == _fieldu
975-
):
976-
url_idx.pop(_key)
977-
978-
return url_idx
968+
if not field_idx:
969+
return url_idx
970+
971+
nonoverlapping_urls = []
972+
973+
any_param_start = min(e[0] for e in field_idx)
974+
for _key, _value in enumerate(url_idx):
975+
if _value[1] < any_param_start:
976+
nonoverlapping_urls.append(_value)
977+
return nonoverlapping_urls
978+

tests/_data/string_files/do_format_docstrings.toml

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -213,3 +213,29 @@ instring='''"""
213213
eBay kinda suss
214214
"""'''
215215
outstring='''"""eBay kinda suss."""'''
216+
217+
[issue_263]
218+
[issue_263.sphinx]
219+
# the `xx.\n\n` ensures there are a summary and a description sections
220+
# the `:param a:` creates a field
221+
# the `b`s create text that is long enough to trigger a line wrap without being so long that they count as code
222+
# the `s3://cccc.` is a url
223+
instring='''"""xx.
224+
225+
:param a: bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb s3://cccc.
226+
"""'''
227+
outstring='''"""xx.
228+
229+
:param a: bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb
230+
s3://cccc.
231+
"""'''
232+
[issue_263.epytext]
233+
instring='''"""xx.
234+
235+
@param a: bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb s3://cccc.
236+
"""'''
237+
outstring='''"""xx.
238+
239+
@param a: bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb
240+
s3://cccc.
241+
"""'''

tests/formatter/test_do_format_docstring.py

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -337,3 +337,24 @@ def test_format_docstring_with_non_cap_words(self, test_args, args):
337337
INDENTATION,
338338
instring,
339339
)
340+
341+
@pytest.mark.unit
342+
@pytest.mark.parametrize("args", [["--style", "sphinx", ""], ["--style", "epytext", ""]])
343+
def test_do_not_double_process_urls(self, test_args, args):
344+
"""Do not double-process urls in fields
345+
346+
See issue #263
347+
"""
348+
style = args[1]
349+
350+
uut = Formatter(
351+
test_args,
352+
sys.stderr,
353+
sys.stdin,
354+
sys.stdout,
355+
)
356+
357+
instring = self.TEST_STRINGS["issue_263"][style]["instring"]
358+
outstring = self.TEST_STRINGS["issue_263"][style]["outstring"]
359+
360+
assert outstring == uut._do_format_docstring(INDENTATION, instring, )

tests/test_syntax_functions.py

Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,12 +34,14 @@
3434
do_find_links()
3535
do_skip_link()
3636
"""
37+
import textwrap
3738

3839
# Third Party Imports
3940
import pytest
4041

4142
# docformatter Package Imports
4243
import docformatter
44+
from docformatter import do_split_description
4345

4446

4547
class TestURLHandlers:
@@ -159,3 +161,76 @@ def test_find_double_backtick_directives(self):
159161
" Since a mail could be ``Cc``'d to two lists with different ``Reply-To`` munging"
160162
"options set."
161163
)
164+
165+
166+
class TestSplitDescription:
167+
"""Class for testing the function to process the description
168+
169+
Includes tests for:
170+
- do_split_description()
171+
172+
"""
173+
med_str = "m"*40 # long enough that 2 won't fit on a line
174+
indent = " "
175+
176+
def do_test(self, text):
177+
return do_split_description(textwrap.dedent(text), self.indent, 72, "sphinx")
178+
179+
def indent_all(self, strs):
180+
return [self.indent + s for s in strs]
181+
182+
@pytest.mark.unit
183+
def test_split_description_url_outside_param(self):
184+
assert self.do_test(
185+
f"""\
186+
{self.med_str} https://{self.med_str}
187+
:param a: {self.med_str}
188+
"""
189+
) == self.indent_all([
190+
self.med_str,
191+
f"https://{self.med_str}",
192+
f":param a: {self.med_str}",
193+
])
194+
195+
@pytest.mark.unit
196+
def test_split_description_single_url_in_param(self):
197+
assert self.do_test(
198+
f"""\
199+
{self.med_str}
200+
:param a: {self.med_str} https://{self.med_str}a
201+
"""
202+
) == self.indent_all([
203+
self.med_str,
204+
f":param a: {self.med_str}",
205+
self.indent + f"https://{self.med_str}a",
206+
])
207+
208+
@pytest.mark.unit
209+
def test_split_description_single_url_in_multiple_params(self):
210+
assert self.do_test(
211+
f"""\
212+
{self.med_str}
213+
:param a: {self.med_str} https://{self.med_str}a
214+
:param b: {self.med_str} https://{self.med_str}b
215+
"""
216+
) == self.indent_all([
217+
self.med_str,
218+
f":param a: {self.med_str}",
219+
self.indent + f"https://{self.med_str}a",
220+
f":param b: {self.med_str}",
221+
self.indent + f"https://{self.med_str}b",
222+
])
223+
224+
@pytest.mark.unit
225+
def test_split_description_multiple_urls_in_param(self):
226+
assert self.do_test(
227+
f"""\
228+
{self.med_str}
229+
:param a: {self.med_str} https://{self.med_str}0 https://{self.med_str}1
230+
"""
231+
) == self.indent_all([
232+
self.med_str,
233+
f":param a: {self.med_str}",
234+
self.indent + f"https://{self.med_str}0",
235+
self.indent + f"https://{self.med_str}1",
236+
])

0 commit comments

Comments
 (0)