format-docstring 0.1.1__tar.gz → 0.1.3__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (93) hide show
  1. {format_docstring-0.1.1 → format_docstring-0.1.3}/.pre-commit-config.yaml +1 -1
  2. {format_docstring-0.1.1 → format_docstring-0.1.3}/CHANGELOG.md +14 -0
  3. {format_docstring-0.1.1 → format_docstring-0.1.3}/PKG-INFO +12 -6
  4. {format_docstring-0.1.1 → format_docstring-0.1.3}/README.md +11 -5
  5. {format_docstring-0.1.1 → format_docstring-0.1.3}/format_docstring/line_wrap_numpy.py +1 -1
  6. {format_docstring-0.1.1 → format_docstring-0.1.3}/format_docstring/line_wrap_utils.py +92 -3
  7. {format_docstring-0.1.1 → format_docstring-0.1.3}/format_docstring.egg-info/PKG-INFO +12 -6
  8. {format_docstring-0.1.1 → format_docstring-0.1.3}/pyproject.toml +1 -1
  9. {format_docstring-0.1.1 → format_docstring-0.1.3}/tests/test_data/end_to_end/numpy/contents_that_are_not_wrapped.txt +2 -0
  10. {format_docstring-0.1.1 → format_docstring-0.1.3}/tests/test_data/end_to_end/numpy/single_line_docstring.txt +22 -0
  11. {format_docstring-0.1.1 → format_docstring-0.1.3}/tests/test_data/line_wrap/numpy/contents_that_are_not_wrapped.txt +2 -0
  12. {format_docstring-0.1.1 → format_docstring-0.1.3}/tests/test_line_wrap_numpy.py +1 -1
  13. {format_docstring-0.1.1 → format_docstring-0.1.3}/tests/test_line_wrap_utils.py +106 -4
  14. {format_docstring-0.1.1 → format_docstring-0.1.3}/.github/workflows/python-package.yml +0 -0
  15. {format_docstring-0.1.1 → format_docstring-0.1.3}/.github/workflows/python-publish.yml +0 -0
  16. {format_docstring-0.1.1 → format_docstring-0.1.3}/.gitignore +0 -0
  17. {format_docstring-0.1.1 → format_docstring-0.1.3}/.pre-commit-hooks.yaml +0 -0
  18. {format_docstring-0.1.1 → format_docstring-0.1.3}/CLAUDE.md +0 -0
  19. {format_docstring-0.1.1 → format_docstring-0.1.3}/LICENSE +0 -0
  20. {format_docstring-0.1.1 → format_docstring-0.1.3}/format_docstring/__init__.py +0 -0
  21. {format_docstring-0.1.1 → format_docstring-0.1.3}/format_docstring/base_fixer.py +0 -0
  22. {format_docstring-0.1.1 → format_docstring-0.1.3}/format_docstring/config.py +0 -0
  23. {format_docstring-0.1.1 → format_docstring-0.1.3}/format_docstring/docstring_rewriter.py +0 -0
  24. {format_docstring-0.1.1 → format_docstring-0.1.3}/format_docstring/line_wrap_google.py +0 -0
  25. {format_docstring-0.1.1 → format_docstring-0.1.3}/format_docstring/main_jupyter.py +0 -0
  26. {format_docstring-0.1.1 → format_docstring-0.1.3}/format_docstring/main_py.py +0 -0
  27. {format_docstring-0.1.1 → format_docstring-0.1.3}/format_docstring.egg-info/SOURCES.txt +0 -0
  28. {format_docstring-0.1.1 → format_docstring-0.1.3}/format_docstring.egg-info/dependency_links.txt +0 -0
  29. {format_docstring-0.1.1 → format_docstring-0.1.3}/format_docstring.egg-info/entry_points.txt +0 -0
  30. {format_docstring-0.1.1 → format_docstring-0.1.3}/format_docstring.egg-info/requires.txt +0 -0
  31. {format_docstring-0.1.1 → format_docstring-0.1.3}/format_docstring.egg-info/top_level.txt +0 -0
  32. {format_docstring-0.1.1 → format_docstring-0.1.3}/muff.toml +0 -0
  33. {format_docstring-0.1.1 → format_docstring-0.1.3}/requirements.dev +0 -0
  34. {format_docstring-0.1.1 → format_docstring-0.1.3}/setup.cfg +0 -0
  35. {format_docstring-0.1.1 → format_docstring-0.1.3}/tests/__init__.py +0 -0
  36. {format_docstring-0.1.1 → format_docstring-0.1.3}/tests/helpers.py +0 -0
  37. {format_docstring-0.1.1 → format_docstring-0.1.3}/tests/test_config.py +0 -0
  38. {format_docstring-0.1.1 → format_docstring-0.1.3}/tests/test_data/end_to_end/numpy/README.md +0 -0
  39. {format_docstring-0.1.1 → format_docstring-0.1.3}/tests/test_data/end_to_end/numpy/colon_spacing_fix.txt +0 -0
  40. {format_docstring-0.1.1 → format_docstring-0.1.3}/tests/test_data/end_to_end/numpy/default_value_standardization.txt +0 -0
  41. {format_docstring-0.1.1 → format_docstring-0.1.3}/tests/test_data/end_to_end/numpy/empty_lines_are_respected.txt +0 -0
  42. {format_docstring-0.1.1 → format_docstring-0.1.3}/tests/test_data/end_to_end/numpy/existing_linebreaks_should_not_be_respected.txt +0 -0
  43. {format_docstring-0.1.1 → format_docstring-0.1.3}/tests/test_data/end_to_end/numpy/four_level_nested_classes.txt +0 -0
  44. {format_docstring-0.1.1 → format_docstring-0.1.3}/tests/test_data/end_to_end/numpy/indent_four_levels_16_spaces_width_10.txt +0 -0
  45. {format_docstring-0.1.1 → format_docstring-0.1.3}/tests/test_data/end_to_end/numpy/indent_misaligned_all.txt +0 -0
  46. {format_docstring-0.1.1 → format_docstring-0.1.3}/tests/test_data/end_to_end/numpy/indent_two_levels_8_spaces.txt +0 -0
  47. {format_docstring-0.1.1 → format_docstring-0.1.3}/tests/test_data/end_to_end/numpy/line_length_2.txt +0 -0
  48. {format_docstring-0.1.1 → format_docstring-0.1.3}/tests/test_data/end_to_end/numpy/mismatched_underlines.txt +0 -0
  49. {format_docstring-0.1.1 → format_docstring-0.1.3}/tests/test_data/end_to_end/numpy/mismatched_underlines_one_dash.txt +0 -0
  50. {format_docstring-0.1.1 → format_docstring-0.1.3}/tests/test_data/end_to_end/numpy/mismatched_underlines_two_dashes.txt +0 -0
  51. {format_docstring-0.1.1 → format_docstring-0.1.3}/tests/test_data/end_to_end/numpy/module_level_docstring.txt +0 -0
  52. {format_docstring-0.1.1 → format_docstring-0.1.3}/tests/test_data/end_to_end/numpy/new_lines_before_and_after.txt +0 -0
  53. {format_docstring-0.1.1 → format_docstring-0.1.3}/tests/test_data/end_to_end/numpy/param_signature_without_type.txt +0 -0
  54. {format_docstring-0.1.1 → format_docstring-0.1.3}/tests/test_data/end_to_end/numpy/parameters_returns_raises_wrapping.txt +0 -0
  55. {format_docstring-0.1.1 → format_docstring-0.1.3}/tests/test_data/end_to_end/numpy/returns_signature_and_description.txt +0 -0
  56. {format_docstring-0.1.1 → format_docstring-0.1.3}/tests/test_data/end_to_end/numpy/section_title_fixed.txt +0 -0
  57. {format_docstring-0.1.1 → format_docstring-0.1.3}/tests/test_data/end_to_end/numpy/sections_notes_examples.txt +0 -0
  58. {format_docstring-0.1.1 → format_docstring-0.1.3}/tests/test_data/end_to_end/numpy/signature_line_is_not_wrapped.txt +0 -0
  59. {format_docstring-0.1.1 → format_docstring-0.1.3}/tests/test_data/end_to_end/numpy/texts_are_rewrapped.txt +0 -0
  60. {format_docstring-0.1.1 → format_docstring-0.1.3}/tests/test_data/end_to_end/numpy/very_long_unbreakable_word.txt +0 -0
  61. {format_docstring-0.1.1 → format_docstring-0.1.3}/tests/test_data/integration_test/numpy/after.ipynb +0 -0
  62. {format_docstring-0.1.1 → format_docstring-0.1.3}/tests/test_data/integration_test/numpy/after.py +0 -0
  63. {format_docstring-0.1.1 → format_docstring-0.1.3}/tests/test_data/integration_test/numpy/after_50.ipynb +0 -0
  64. {format_docstring-0.1.1 → format_docstring-0.1.3}/tests/test_data/integration_test/numpy/after_50.py +0 -0
  65. {format_docstring-0.1.1 → format_docstring-0.1.3}/tests/test_data/integration_test/numpy/before.ipynb +0 -0
  66. {format_docstring-0.1.1 → format_docstring-0.1.3}/tests/test_data/integration_test/numpy/before.py +0 -0
  67. {format_docstring-0.1.1 → format_docstring-0.1.3}/tests/test_data/line_wrap/numpy/README.md +0 -0
  68. {format_docstring-0.1.1 → format_docstring-0.1.3}/tests/test_data/line_wrap/numpy/colon_spacing_fix.txt +0 -0
  69. {format_docstring-0.1.1 → format_docstring-0.1.3}/tests/test_data/line_wrap/numpy/default_value_standardization.txt +0 -0
  70. {format_docstring-0.1.1 → format_docstring-0.1.3}/tests/test_data/line_wrap/numpy/empty_lines_are_respected.txt +0 -0
  71. {format_docstring-0.1.1 → format_docstring-0.1.3}/tests/test_data/line_wrap/numpy/existing_linebreaks_should_not_be_respected.txt +0 -0
  72. {format_docstring-0.1.1 → format_docstring-0.1.3}/tests/test_data/line_wrap/numpy/indent_four_levels_16_spaces_width_10.txt +0 -0
  73. {format_docstring-0.1.1 → format_docstring-0.1.3}/tests/test_data/line_wrap/numpy/indent_two_levels_8_spaces.txt +0 -0
  74. {format_docstring-0.1.1 → format_docstring-0.1.3}/tests/test_data/line_wrap/numpy/line_length_2.txt +0 -0
  75. {format_docstring-0.1.1 → format_docstring-0.1.3}/tests/test_data/line_wrap/numpy/mismatched_underlines.txt +0 -0
  76. {format_docstring-0.1.1 → format_docstring-0.1.3}/tests/test_data/line_wrap/numpy/mismatched_underlines_one_dash.txt +0 -0
  77. {format_docstring-0.1.1 → format_docstring-0.1.3}/tests/test_data/line_wrap/numpy/mismatched_underlines_two_dashes.txt +0 -0
  78. {format_docstring-0.1.1 → format_docstring-0.1.3}/tests/test_data/line_wrap/numpy/module_level_docstring.txt +0 -0
  79. {format_docstring-0.1.1 → format_docstring-0.1.3}/tests/test_data/line_wrap/numpy/param_signature_without_type.txt +0 -0
  80. {format_docstring-0.1.1 → format_docstring-0.1.3}/tests/test_data/line_wrap/numpy/parameters_returns_raises_wrapping.txt +0 -0
  81. {format_docstring-0.1.1 → format_docstring-0.1.3}/tests/test_data/line_wrap/numpy/returns_signature_and_description.txt +0 -0
  82. {format_docstring-0.1.1 → format_docstring-0.1.3}/tests/test_data/line_wrap/numpy/section_title_fixed.txt +0 -0
  83. {format_docstring-0.1.1 → format_docstring-0.1.3}/tests/test_data/line_wrap/numpy/sections_notes_examples.txt +0 -0
  84. {format_docstring-0.1.1 → format_docstring-0.1.3}/tests/test_data/line_wrap/numpy/signature_line_is_not_wrapped.txt +0 -0
  85. {format_docstring-0.1.1 → format_docstring-0.1.3}/tests/test_data/line_wrap/numpy/texts_are_rewrapped.txt +0 -0
  86. {format_docstring-0.1.1 → format_docstring-0.1.3}/tests/test_data/line_wrap/numpy/very_long_unbreakable_word.txt +0 -0
  87. {format_docstring-0.1.1 → format_docstring-0.1.3}/tests/test_data/playground.py +0 -0
  88. {format_docstring-0.1.1 → format_docstring-0.1.3}/tests/test_docstring_rewriter.py +0 -0
  89. {format_docstring-0.1.1 → format_docstring-0.1.3}/tests/test_line_wrap_google.py +0 -0
  90. {format_docstring-0.1.1 → format_docstring-0.1.3}/tests/test_main_jupyter.py +0 -0
  91. {format_docstring-0.1.1 → format_docstring-0.1.3}/tests/test_main_py.py +0 -0
  92. {format_docstring-0.1.1 → format_docstring-0.1.3}/tests/test_playground.py +0 -0
  93. {format_docstring-0.1.1 → format_docstring-0.1.3}/tox.ini +0 -0
@@ -37,6 +37,6 @@ repos:
37
37
  args: [--wrap, '79', --number]
38
38
  additional_dependencies: [mdformat-tables]
39
39
  - repo: https://github.com/jsh9/markdown-toc-creator
40
- rev: 0.0.10
40
+ rev: 0.0.11
41
41
  hooks:
42
42
  - id: markdown-toc-creator
@@ -6,6 +6,20 @@ The format is based on
6
6
  [Keep a Changelog](https://keepachangelog.com/en/1.1.0/), and this project
7
7
  adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
8
8
 
9
+ ## [0.1.3] - 2025-10-12
10
+
11
+ - Fixed
12
+ - A bug in counting line length for single-line docstrings
13
+ - Full diff
14
+ - https://github.com/jsh9/format-docstring/compare/0.1.2...0.1.3
15
+
16
+ ## [0.1.2] - 2025-10-08
17
+
18
+ - Added
19
+ - Support for 1 blank line after `::`
20
+ - Full diff
21
+ - https://github.com/jsh9/format-docstring/compare/0.1.1...0.1.2
22
+
9
23
  ## [0.1.1] - 2025-10-06
10
24
 
11
25
  - Fixed
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: format-docstring
3
- Version: 0.1.1
3
+ Version: 0.1.3
4
4
  Summary: A Python formatter to wrap/adjust docstring lines
5
5
  Author-email: jsh9 <25124332+jsh9@users.noreply.github.com>
6
6
  Maintainer-email: jsh9 <25124332+jsh9@users.noreply.github.com>
@@ -109,7 +109,8 @@ def example_function(param1, param2, option='default'):
109
109
 
110
110
  Examples
111
111
  --------
112
- Code examples with >>> prompts are preserved without wrapping:
112
+ Within the "Examples" section, code with >>> prompts are preserved without
113
+ wrapping:
113
114
 
114
115
  >>> result = example_function('test', 42, option='custom_value_with_a_very_long_name_that_exceeds_line_length')
115
116
  >>> print(result)
@@ -124,11 +125,16 @@ def example_function(param1, param2, option='default'):
124
125
  Params Yes Signature lines preserved
125
126
  =========== ================== ===============================
126
127
 
127
- Content following double colons (::) is preserved::
128
+ Contents following double colons (`::`) are preserved::
128
129
 
129
- - This indented block after :: is not wrapped
130
- - Even if lines are very long they stay intact
131
- - Useful for code blocks or literal content
130
+ P(B|A) P(A)
131
+ P(A|B) = -------------
132
+ P(B)
133
+
134
+ Even if there isn't an extra blank line after `::`, the contents are still
135
+ preserved::
136
+ _______
137
+ σ = √ Var(X)
132
138
 
133
139
  Regular bullet lists are also preserved:
134
140
 
@@ -76,7 +76,8 @@ def example_function(param1, param2, option='default'):
76
76
 
77
77
  Examples
78
78
  --------
79
- Code examples with >>> prompts are preserved without wrapping:
79
+ Within the "Examples" section, code with >>> prompts are preserved without
80
+ wrapping:
80
81
 
81
82
  >>> result = example_function('test', 42, option='custom_value_with_a_very_long_name_that_exceeds_line_length')
82
83
  >>> print(result)
@@ -91,11 +92,16 @@ def example_function(param1, param2, option='default'):
91
92
  Params Yes Signature lines preserved
92
93
  =========== ================== ===============================
93
94
 
94
- Content following double colons (::) is preserved::
95
+ Contents following double colons (`::`) are preserved::
95
96
 
96
- - This indented block after :: is not wrapped
97
- - Even if lines are very long they stay intact
98
- - Useful for code blocks or literal content
97
+ P(B|A) P(A)
98
+ P(A|B) = -------------
99
+ P(B)
100
+
101
+ Even if there isn't an extra blank line after `::`, the contents are still
102
+ preserved::
103
+ _______
104
+ σ = √ Var(X)
99
105
 
100
106
  Regular bullet lists are also preserved:
101
107
 
@@ -377,7 +377,7 @@ def handle_single_line_docstring(
377
377
  if '\n' in whole_docstring_literal: # multi-line: do not handle
378
378
  return whole_docstring_literal
379
379
 
380
- if docstring_ending_col >= line_length: # whole docstring exceeds limit
380
+ if docstring_ending_col > line_length: # whole docstring exceeds limit
381
381
  num_leading_indent: int = docstring_starting_col
382
382
  parts: list[str] = whole_docstring_literal.split(docstring_content)
383
383
  prefix: str = parts[0]
@@ -66,14 +66,79 @@ def process_temp_output(
66
66
  temp_out: list[str | list[str]],
67
67
  width: int,
68
68
  ) -> list[str]:
69
- """Wrap the `list[str]` elements in `temp_out`."""
69
+ """
70
+ Wrap the `list[str]` elements in `temp_out`.
71
+
72
+ To preserve literal blocks indicated by ``::``, the function first scans
73
+ ``temp_out`` for the pattern ``<line ending with '::'>``, followed by
74
+ ``''`` (exactly 1 empty line), followed by non-empty content. When found,
75
+ those three entries are merged into
76
+ a single ``list[str]`` so the literal block (including the separating blank
77
+ line) is wrapped as one unit.
78
+ """
79
+
80
+ def _to_list(element: str | list[str]) -> list[str]:
81
+ return [element] if isinstance(element, str) else list(element)
82
+
83
+ def _ends_with_literal_block_marker(element: str | list[str]) -> bool:
84
+ if isinstance(element, str):
85
+ return element.endswith('::')
86
+
87
+ if not element:
88
+ return False
89
+
90
+ return element[-1].endswith('::')
91
+
92
+ def _is_empty_string(element: str | list[str]) -> bool:
93
+ return isinstance(element, str) and element == ''
94
+
95
+ def _has_content(element: str | list[str]) -> bool:
96
+ if isinstance(element, str):
97
+ return element != ''
98
+
99
+ return any(line != '' for line in element)
100
+
101
+ merged_temp_out: list[str | list[str]] = []
102
+ idx = 0
103
+ while idx < len(temp_out):
104
+ current = temp_out[idx]
105
+ next_idx = idx + 1
106
+ next_next_idx = idx + 2
107
+
108
+ if (
109
+ _ends_with_literal_block_marker(current)
110
+ and next_next_idx < len(temp_out)
111
+ and _is_empty_string(temp_out[next_idx])
112
+ and _has_content(temp_out[next_next_idx])
113
+ ):
114
+ merged_element: list[str] = []
115
+ merged_element.extend(_to_list(current))
116
+ merged_element.extend(_to_list(temp_out[next_idx]))
117
+ merged_element.extend(_to_list(temp_out[next_next_idx]))
118
+ merged_temp_out.append(merged_element)
119
+ idx += 3
120
+ continue
121
+
122
+ merged_temp_out.append(current)
123
+ idx += 1
124
+
70
125
  out: list[str] = []
71
126
 
72
- for element in temp_out:
127
+ for element in merged_temp_out:
73
128
  if isinstance(element, str):
74
129
  out.append(element)
75
130
  elif isinstance(element, list):
76
131
  wrapped: list[str] = wrap_preserving_indent(element, width)
132
+ if (
133
+ '' in element
134
+ and '' not in wrapped
135
+ and element.index('') < len(element) - 1
136
+ ):
137
+ insertion_idx = min(element.index(''), len(wrapped))
138
+ wrapped = (
139
+ wrapped[:insertion_idx] + [''] + wrapped[insertion_idx:]
140
+ )
141
+
77
142
  out.extend(wrapped)
78
143
  else:
79
144
  raise RuntimeError("Something's wrong. Please contact the author.")
@@ -185,7 +250,31 @@ def _wrap_text_segment(lines: list[str], width: int) -> list[str]:
185
250
  if result and result[-1] == '':
186
251
  result.pop()
187
252
 
188
- return result if result else lines
253
+ result_: list[str] = result if result else lines
254
+
255
+ return _add_back_leading_or_trailing_newline(
256
+ original_lines=lines,
257
+ wrapped_lines=result_,
258
+ )
259
+
260
+
261
+ def _add_back_leading_or_trailing_newline(
262
+ original_lines: list[str],
263
+ wrapped_lines: list[str],
264
+ ) -> list[str]:
265
+ if len(original_lines) == 0 or len(wrapped_lines) == 0:
266
+ return wrapped_lines
267
+
268
+ new_result: list[str] = []
269
+ if original_lines[0] == '':
270
+ new_result = [''] + wrapped_lines
271
+ else:
272
+ new_result = wrapped_lines
273
+
274
+ if original_lines[-1] == '':
275
+ return new_result + ['']
276
+
277
+ return new_result
189
278
 
190
279
 
191
280
  def merge_lines_and_strip(text: str) -> str:
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: format-docstring
3
- Version: 0.1.1
3
+ Version: 0.1.3
4
4
  Summary: A Python formatter to wrap/adjust docstring lines
5
5
  Author-email: jsh9 <25124332+jsh9@users.noreply.github.com>
6
6
  Maintainer-email: jsh9 <25124332+jsh9@users.noreply.github.com>
@@ -109,7 +109,8 @@ def example_function(param1, param2, option='default'):
109
109
 
110
110
  Examples
111
111
  --------
112
- Code examples with >>> prompts are preserved without wrapping:
112
+ Within the "Examples" section, code with >>> prompts are preserved without
113
+ wrapping:
113
114
 
114
115
  >>> result = example_function('test', 42, option='custom_value_with_a_very_long_name_that_exceeds_line_length')
115
116
  >>> print(result)
@@ -124,11 +125,16 @@ def example_function(param1, param2, option='default'):
124
125
  Params Yes Signature lines preserved
125
126
  =========== ================== ===============================
126
127
 
127
- Content following double colons (::) is preserved::
128
+ Contents following double colons (`::`) are preserved::
128
129
 
129
- - This indented block after :: is not wrapped
130
- - Even if lines are very long they stay intact
131
- - Useful for code blocks or literal content
130
+ P(B|A) P(A)
131
+ P(A|B) = -------------
132
+ P(B)
133
+
134
+ Even if there isn't an extra blank line after `::`, the contents are still
135
+ preserved::
136
+ _______
137
+ σ = √ Var(X)
132
138
 
133
139
  Regular bullet lists are also preserved:
134
140
 
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "format-docstring"
7
- version = "0.1.1"
7
+ version = "0.1.3"
8
8
  description = "A Python formatter to wrap/adjust docstring lines"
9
9
  readme = "README.md"
10
10
  license = {text = "MIT"}
@@ -7,6 +7,7 @@ def func1():
7
7
  def func3():
8
8
  """
9
9
  Below is a formula that should not be wrapped. Here are some more contents that are arbitrary just to make the line length quite long so that we can test how it can be wrapped. This paragraph would end with two colons to signal that the contents below should not be wrapped::
10
+
10
11
  x^alpha * beta
11
12
  y(x) = --------------------------------
12
13
  1 gamma^a * tau
@@ -59,6 +60,7 @@ def func1():
59
60
  so that we can test how it can be wrapped. This paragraph would end
60
61
  with two colons to signal that the contents below should not be
61
62
  wrapped::
63
+
62
64
  x^alpha * beta
63
65
  y(x) = --------------------------------
64
66
  1 gamma^a * tau
@@ -25,6 +25,16 @@ def func3():
25
25
  """
26
26
  pass
27
27
 
28
+
29
+ def func4():
30
+ """This line has the right number of chars that it does not exceed limit"""
31
+ pass
32
+
33
+
34
+ def func5():
35
+ r"""This line has the right number of chars that it exceeds limit by 1..."""
36
+ pass
37
+
28
38
  **********
29
39
  def func1():
30
40
  """
@@ -53,3 +63,15 @@ def func3():
53
63
  This line is already formatted so we should not re-wrap it.
54
64
  """
55
65
  pass
66
+
67
+
68
+ def func4():
69
+ """This line has the right number of chars that it does not exceed limit"""
70
+ pass
71
+
72
+
73
+ def func5():
74
+ r"""
75
+ This line has the right number of chars that it exceeds limit by 1...
76
+ """
77
+ pass
@@ -3,6 +3,7 @@ LINE_LENGTH: 79
3
3
  **********
4
4
 
5
5
  Below is a formula that should not be wrapped. Here are some more contents that are arbitrary just to make the line length quite long so that we can test how it can be wrapped. This paragraph would end with two colons to signal that the contents below should not be wrapped::
6
+
6
7
  x^alpha * beta
7
8
  y(x) = --------------------------------
8
9
  1 gamma^a * tau
@@ -48,6 +49,7 @@ Below is a formula that should not be wrapped. Here are some more contents that
48
49
  are arbitrary just to make the line length quite long so that we can test how
49
50
  it can be wrapped. This paragraph would end with two colons to signal that the
50
51
  contents below should not be wrapped::
52
+
51
53
  x^alpha * beta
52
54
  y(x) = --------------------------------
53
55
  1 gamma^a * tau
@@ -35,7 +35,7 @@ def test_wrap_docstring_single_case() -> None:
35
35
  the test case file that's producing errors.
36
36
  """
37
37
  filename, length, before, after = load_case_from_file(
38
- DATA_DIR / 'mismatched_underlines_two_dashes.txt'
38
+ DATA_DIR / 'contents_that_are_not_wrapped.txt'
39
39
  )
40
40
  out = wrap_docstring(before, line_length=length, docstring_style='numpy')
41
41
  assert out.strip('\n') == after.strip('\n')
@@ -9,6 +9,7 @@ from format_docstring.line_wrap_utils import (
9
9
  is_bulleted_list,
10
10
  is_rST_table,
11
11
  merge_lines_and_strip,
12
+ process_temp_output,
12
13
  segment_lines_by_wrappability,
13
14
  wrap_preserving_indent,
14
15
  )
@@ -125,7 +126,7 @@ from format_docstring.line_wrap_utils import (
125
126
  # Test with rST table (should be preserved)
126
127
  (
127
128
  [
128
- 'Here is some text that should wrap.',
129
+ 'Here is some text that should wrap. 1.',
129
130
  '',
130
131
  '+------+-----+',
131
132
  '| Name | Age |',
@@ -138,12 +139,14 @@ from format_docstring.line_wrap_utils import (
138
139
  20,
139
140
  [
140
141
  'Here is some text',
141
- 'that should wrap.',
142
+ 'that should wrap. 1.',
143
+ '',
142
144
  '+------+-----+',
143
145
  '| Name | Age |',
144
146
  '+------+-----+',
145
147
  '| John | 25 |',
146
148
  '+------+-----+',
149
+ '',
147
150
  'More text that',
148
151
  'should wrap.',
149
152
  ],
@@ -151,7 +154,7 @@ from format_docstring.line_wrap_utils import (
151
154
  # Test with bulleted list (should be preserved)
152
155
  (
153
156
  [
154
- 'This is a very long line of text that should be wrapped.',
157
+ 'This is a very long line of text that should be wrapped. 2',
155
158
  '',
156
159
  '- First list item that is quite long',
157
160
  '- Second list item that is also long',
@@ -162,9 +165,11 @@ from format_docstring.line_wrap_utils import (
162
165
  [
163
166
  'This is a very long line',
164
167
  'of text that should be',
165
- 'wrapped.',
168
+ 'wrapped. 2',
169
+ '',
166
170
  '- First list item that is quite long',
167
171
  '- Second list item that is also long',
172
+ '',
168
173
  'Another long line that',
169
174
  'should be wrapped.',
170
175
  ],
@@ -218,6 +223,103 @@ def test_finalize_lines(
218
223
  assert finalize_lines(lines, leading_indent) == expected
219
224
 
220
225
 
226
+ @pytest.mark.parametrize(
227
+ 'temp_out,width,expected',
228
+ [
229
+ (
230
+ [
231
+ 'Examples::',
232
+ '',
233
+ [' code line 1', ' code line 2'],
234
+ ],
235
+ 20,
236
+ [
237
+ 'Examples::',
238
+ '',
239
+ ' code line 1',
240
+ ' code line 2',
241
+ ],
242
+ ),
243
+ (
244
+ [
245
+ 'Examples::',
246
+ '',
247
+ [
248
+ ' literal block with long text that should remain'
249
+ ' on one line even though width is short'
250
+ ],
251
+ ],
252
+ 30,
253
+ [
254
+ 'Examples::',
255
+ '',
256
+ (
257
+ ' literal block with long text that should remain'
258
+ ' on one line even though width is short'
259
+ ),
260
+ ],
261
+ ),
262
+ (
263
+ [
264
+ 'Examples::',
265
+ '',
266
+ '', # 2 empty lines: not protected by `::` above -> will wrap
267
+ [
268
+ (
269
+ ' literal block with long text that should remain'
270
+ ' on one line even though width is short'
271
+ )
272
+ ],
273
+ ],
274
+ 30,
275
+ [
276
+ 'Examples::',
277
+ '',
278
+ '',
279
+ ' literal block with long',
280
+ ' text that should remain on',
281
+ ' one line even though width',
282
+ ' is short',
283
+ ],
284
+ ),
285
+ (
286
+ [
287
+ 'Examples::',
288
+ 'no blank separator',
289
+ [' code line 1', ' code line 2'],
290
+ ],
291
+ 40,
292
+ [
293
+ 'Examples::',
294
+ 'no blank separator',
295
+ ' code line 1 code line 2',
296
+ ],
297
+ ),
298
+ (
299
+ [
300
+ 'Examples::',
301
+ '',
302
+ '',
303
+ 'Trailing text',
304
+ ],
305
+ 25,
306
+ [
307
+ 'Examples::',
308
+ '',
309
+ '',
310
+ 'Trailing text',
311
+ ],
312
+ ),
313
+ ],
314
+ )
315
+ def test_process_temp_output_merges_literal_block(
316
+ temp_out: list[str | list[str]],
317
+ width: int,
318
+ expected: list[str],
319
+ ) -> None:
320
+ assert process_temp_output(temp_out, width) == expected
321
+
322
+
221
323
  @pytest.mark.parametrize(
222
324
  'text,expected',
223
325
  [