format-docstring 0.2.4__tar.gz → 0.2.5__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 (109) hide show
  1. {format_docstring-0.2.4 → format_docstring-0.2.5}/.gitignore +3 -0
  2. {format_docstring-0.2.4 → format_docstring-0.2.5}/CHANGELOG.md +8 -0
  3. {format_docstring-0.2.4 → format_docstring-0.2.5}/PKG-INFO +1 -1
  4. {format_docstring-0.2.4 → format_docstring-0.2.5}/format_docstring/line_wrap_numpy.py +64 -13
  5. {format_docstring-0.2.4 → format_docstring-0.2.5}/format_docstring.egg-info/PKG-INFO +1 -1
  6. {format_docstring-0.2.4 → format_docstring-0.2.5}/pyproject.toml +1 -1
  7. {format_docstring-0.2.4 → format_docstring-0.2.5}/tests/test_data/end_to_end/numpy/signature_sync_yields.txt +49 -1
  8. {format_docstring-0.2.4 → format_docstring-0.2.5}/.github/workflows/python-package.yml +0 -0
  9. {format_docstring-0.2.4 → format_docstring-0.2.5}/.github/workflows/python-publish.yml +0 -0
  10. {format_docstring-0.2.4 → format_docstring-0.2.5}/.pre-commit-config.yaml +0 -0
  11. {format_docstring-0.2.4 → format_docstring-0.2.5}/.pre-commit-hooks.yaml +0 -0
  12. {format_docstring-0.2.4 → format_docstring-0.2.5}/AGENTS.md +0 -0
  13. {format_docstring-0.2.4 → format_docstring-0.2.5}/LICENSE +0 -0
  14. {format_docstring-0.2.4 → format_docstring-0.2.5}/README.md +0 -0
  15. {format_docstring-0.2.4 → format_docstring-0.2.5}/format_docstring/__init__.py +0 -0
  16. {format_docstring-0.2.4 → format_docstring-0.2.5}/format_docstring/base_fixer.py +0 -0
  17. {format_docstring-0.2.4 → format_docstring-0.2.5}/format_docstring/config.py +0 -0
  18. {format_docstring-0.2.4 → format_docstring-0.2.5}/format_docstring/docstring_rewriter.py +0 -0
  19. {format_docstring-0.2.4 → format_docstring-0.2.5}/format_docstring/line_wrap_google.py +0 -0
  20. {format_docstring-0.2.4 → format_docstring-0.2.5}/format_docstring/line_wrap_utils.py +0 -0
  21. {format_docstring-0.2.4 → format_docstring-0.2.5}/format_docstring/main_jupyter.py +0 -0
  22. {format_docstring-0.2.4 → format_docstring-0.2.5}/format_docstring/main_py.py +0 -0
  23. {format_docstring-0.2.4 → format_docstring-0.2.5}/format_docstring.egg-info/SOURCES.txt +0 -0
  24. {format_docstring-0.2.4 → format_docstring-0.2.5}/format_docstring.egg-info/dependency_links.txt +0 -0
  25. {format_docstring-0.2.4 → format_docstring-0.2.5}/format_docstring.egg-info/entry_points.txt +0 -0
  26. {format_docstring-0.2.4 → format_docstring-0.2.5}/format_docstring.egg-info/requires.txt +0 -0
  27. {format_docstring-0.2.4 → format_docstring-0.2.5}/format_docstring.egg-info/top_level.txt +0 -0
  28. {format_docstring-0.2.4 → format_docstring-0.2.5}/muff.toml +0 -0
  29. {format_docstring-0.2.4 → format_docstring-0.2.5}/requirements.dev +0 -0
  30. {format_docstring-0.2.4 → format_docstring-0.2.5}/setup.cfg +0 -0
  31. {format_docstring-0.2.4 → format_docstring-0.2.5}/tests/__init__.py +0 -0
  32. {format_docstring-0.2.4 → format_docstring-0.2.5}/tests/helpers.py +0 -0
  33. {format_docstring-0.2.4 → format_docstring-0.2.5}/tests/test_base_fixer.py +0 -0
  34. {format_docstring-0.2.4 → format_docstring-0.2.5}/tests/test_config.py +0 -0
  35. {format_docstring-0.2.4 → format_docstring-0.2.5}/tests/test_data/end_to_end/numpy/README.md +0 -0
  36. {format_docstring-0.2.4 → format_docstring-0.2.5}/tests/test_data/end_to_end/numpy/arg_name_is_default.txt +0 -0
  37. {format_docstring-0.2.4 → format_docstring-0.2.5}/tests/test_data/end_to_end/numpy/colon_spacing_fix.txt +0 -0
  38. {format_docstring-0.2.4 → format_docstring-0.2.5}/tests/test_data/end_to_end/numpy/contents_that_are_not_wrapped.txt +0 -0
  39. {format_docstring-0.2.4 → format_docstring-0.2.5}/tests/test_data/end_to_end/numpy/default_value_standardization.txt +0 -0
  40. {format_docstring-0.2.4 → format_docstring-0.2.5}/tests/test_data/end_to_end/numpy/empty_lines_are_respected.txt +0 -0
  41. {format_docstring-0.2.4 → format_docstring-0.2.5}/tests/test_data/end_to_end/numpy/examples_section.txt +0 -0
  42. {format_docstring-0.2.4 → format_docstring-0.2.5}/tests/test_data/end_to_end/numpy/existing_linebreaks_should_not_be_respected.txt +0 -0
  43. {format_docstring-0.2.4 → format_docstring-0.2.5}/tests/test_data/end_to_end/numpy/fix_rst_backticks.txt +0 -0
  44. {format_docstring-0.2.4 → format_docstring-0.2.5}/tests/test_data/end_to_end/numpy/four_level_nested_classes.txt +0 -0
  45. {format_docstring-0.2.4 → format_docstring-0.2.5}/tests/test_data/end_to_end/numpy/indent_four_levels_16_spaces_width_10.txt +0 -0
  46. {format_docstring-0.2.4 → format_docstring-0.2.5}/tests/test_data/end_to_end/numpy/indent_misaligned_all.txt +0 -0
  47. {format_docstring-0.2.4 → format_docstring-0.2.5}/tests/test_data/end_to_end/numpy/indent_two_levels_8_spaces.txt +0 -0
  48. {format_docstring-0.2.4 → format_docstring-0.2.5}/tests/test_data/end_to_end/numpy/line_length_2.txt +0 -0
  49. {format_docstring-0.2.4 → format_docstring-0.2.5}/tests/test_data/end_to_end/numpy/mismatched_underlines.txt +0 -0
  50. {format_docstring-0.2.4 → format_docstring-0.2.5}/tests/test_data/end_to_end/numpy/mismatched_underlines_one_dash.txt +0 -0
  51. {format_docstring-0.2.4 → format_docstring-0.2.5}/tests/test_data/end_to_end/numpy/mismatched_underlines_two_dashes.txt +0 -0
  52. {format_docstring-0.2.4 → format_docstring-0.2.5}/tests/test_data/end_to_end/numpy/module_level_docstring.txt +0 -0
  53. {format_docstring-0.2.4 → format_docstring-0.2.5}/tests/test_data/end_to_end/numpy/new_lines_before_and_after.txt +0 -0
  54. {format_docstring-0.2.4 → format_docstring-0.2.5}/tests/test_data/end_to_end/numpy/no_format_docstring_comment.txt +0 -0
  55. {format_docstring-0.2.4 → format_docstring-0.2.5}/tests/test_data/end_to_end/numpy/param_signature_without_type.txt +0 -0
  56. {format_docstring-0.2.4 → format_docstring-0.2.5}/tests/test_data/end_to_end/numpy/parameters_returns_raises_wrapping.txt +0 -0
  57. {format_docstring-0.2.4 → format_docstring-0.2.5}/tests/test_data/end_to_end/numpy/returns_signature_and_description.txt +0 -0
  58. {format_docstring-0.2.4 → format_docstring-0.2.5}/tests/test_data/end_to_end/numpy/section_headings_with_colons.txt +0 -0
  59. {format_docstring-0.2.4 → format_docstring-0.2.5}/tests/test_data/end_to_end/numpy/section_title_fixed.txt +0 -0
  60. {format_docstring-0.2.4 → format_docstring-0.2.5}/tests/test_data/end_to_end/numpy/sections_notes_examples.txt +0 -0
  61. {format_docstring-0.2.4 → format_docstring-0.2.5}/tests/test_data/end_to_end/numpy/signature_dont_sync_raises.txt +0 -0
  62. {format_docstring-0.2.4 → format_docstring-0.2.5}/tests/test_data/end_to_end/numpy/signature_line_is_not_wrapped.txt +0 -0
  63. {format_docstring-0.2.4 → format_docstring-0.2.5}/tests/test_data/end_to_end/numpy/signature_sync_class_docstrings.txt +0 -0
  64. {format_docstring-0.2.4 → format_docstring-0.2.5}/tests/test_data/end_to_end/numpy/signature_sync_parameters.txt +0 -0
  65. {format_docstring-0.2.4 → format_docstring-0.2.5}/tests/test_data/end_to_end/numpy/signature_sync_returns.txt +0 -0
  66. {format_docstring-0.2.4 → format_docstring-0.2.5}/tests/test_data/end_to_end/numpy/single_line_docstring.txt +0 -0
  67. {format_docstring-0.2.4 → format_docstring-0.2.5}/tests/test_data/end_to_end/numpy/texts_are_rewrapped.txt +0 -0
  68. {format_docstring-0.2.4 → format_docstring-0.2.5}/tests/test_data/end_to_end/numpy/very_long_unbreakable_word.txt +0 -0
  69. {format_docstring-0.2.4 → format_docstring-0.2.5}/tests/test_data/integration_test/numpy/after.ipynb +0 -0
  70. {format_docstring-0.2.4 → format_docstring-0.2.5}/tests/test_data/integration_test/numpy/after.py +0 -0
  71. {format_docstring-0.2.4 → format_docstring-0.2.5}/tests/test_data/integration_test/numpy/after_50.ipynb +0 -0
  72. {format_docstring-0.2.4 → format_docstring-0.2.5}/tests/test_data/integration_test/numpy/after_50.py +0 -0
  73. {format_docstring-0.2.4 → format_docstring-0.2.5}/tests/test_data/integration_test/numpy/before.ipynb +0 -0
  74. {format_docstring-0.2.4 → format_docstring-0.2.5}/tests/test_data/integration_test/numpy/before.py +0 -0
  75. {format_docstring-0.2.4 → format_docstring-0.2.5}/tests/test_data/jupyter/before.ipynb +0 -0
  76. {format_docstring-0.2.4 → format_docstring-0.2.5}/tests/test_data/jupyter/verbose_before.ipynb +0 -0
  77. {format_docstring-0.2.4 → format_docstring-0.2.5}/tests/test_data/line_wrap/numpy/README.md +0 -0
  78. {format_docstring-0.2.4 → format_docstring-0.2.5}/tests/test_data/line_wrap/numpy/colon_spacing_fix.txt +0 -0
  79. {format_docstring-0.2.4 → format_docstring-0.2.5}/tests/test_data/line_wrap/numpy/contents_that_are_not_wrapped.txt +0 -0
  80. {format_docstring-0.2.4 → format_docstring-0.2.5}/tests/test_data/line_wrap/numpy/default_value_standardization.txt +0 -0
  81. {format_docstring-0.2.4 → format_docstring-0.2.5}/tests/test_data/line_wrap/numpy/empty_lines_are_respected.txt +0 -0
  82. {format_docstring-0.2.4 → format_docstring-0.2.5}/tests/test_data/line_wrap/numpy/examples_section.txt +0 -0
  83. {format_docstring-0.2.4 → format_docstring-0.2.5}/tests/test_data/line_wrap/numpy/existing_linebreaks_should_not_be_respected.txt +0 -0
  84. {format_docstring-0.2.4 → format_docstring-0.2.5}/tests/test_data/line_wrap/numpy/fix_rst_backticks.txt +0 -0
  85. {format_docstring-0.2.4 → format_docstring-0.2.5}/tests/test_data/line_wrap/numpy/indent_four_levels_16_spaces_width_10.txt +0 -0
  86. {format_docstring-0.2.4 → format_docstring-0.2.5}/tests/test_data/line_wrap/numpy/indent_two_levels_8_spaces.txt +0 -0
  87. {format_docstring-0.2.4 → format_docstring-0.2.5}/tests/test_data/line_wrap/numpy/line_length_2.txt +0 -0
  88. {format_docstring-0.2.4 → format_docstring-0.2.5}/tests/test_data/line_wrap/numpy/mismatched_underlines.txt +0 -0
  89. {format_docstring-0.2.4 → format_docstring-0.2.5}/tests/test_data/line_wrap/numpy/mismatched_underlines_one_dash.txt +0 -0
  90. {format_docstring-0.2.4 → format_docstring-0.2.5}/tests/test_data/line_wrap/numpy/mismatched_underlines_two_dashes.txt +0 -0
  91. {format_docstring-0.2.4 → format_docstring-0.2.5}/tests/test_data/line_wrap/numpy/module_level_docstring.txt +0 -0
  92. {format_docstring-0.2.4 → format_docstring-0.2.5}/tests/test_data/line_wrap/numpy/param_signature_without_type.txt +0 -0
  93. {format_docstring-0.2.4 → format_docstring-0.2.5}/tests/test_data/line_wrap/numpy/parameters_returns_raises_wrapping.txt +0 -0
  94. {format_docstring-0.2.4 → format_docstring-0.2.5}/tests/test_data/line_wrap/numpy/returns_signature_and_description.txt +0 -0
  95. {format_docstring-0.2.4 → format_docstring-0.2.5}/tests/test_data/line_wrap/numpy/section_headings_with_colons.txt +0 -0
  96. {format_docstring-0.2.4 → format_docstring-0.2.5}/tests/test_data/line_wrap/numpy/section_title_fixed.txt +0 -0
  97. {format_docstring-0.2.4 → format_docstring-0.2.5}/tests/test_data/line_wrap/numpy/sections_notes_examples.txt +0 -0
  98. {format_docstring-0.2.4 → format_docstring-0.2.5}/tests/test_data/line_wrap/numpy/signature_line_is_not_wrapped.txt +0 -0
  99. {format_docstring-0.2.4 → format_docstring-0.2.5}/tests/test_data/line_wrap/numpy/texts_are_rewrapped.txt +0 -0
  100. {format_docstring-0.2.4 → format_docstring-0.2.5}/tests/test_data/line_wrap/numpy/very_long_unbreakable_word.txt +0 -0
  101. {format_docstring-0.2.4 → format_docstring-0.2.5}/tests/test_data/playground.py +0 -0
  102. {format_docstring-0.2.4 → format_docstring-0.2.5}/tests/test_docstring_rewriter.py +0 -0
  103. {format_docstring-0.2.4 → format_docstring-0.2.5}/tests/test_line_wrap_google.py +0 -0
  104. {format_docstring-0.2.4 → format_docstring-0.2.5}/tests/test_line_wrap_numpy.py +0 -0
  105. {format_docstring-0.2.4 → format_docstring-0.2.5}/tests/test_line_wrap_utils.py +0 -0
  106. {format_docstring-0.2.4 → format_docstring-0.2.5}/tests/test_main_jupyter.py +0 -0
  107. {format_docstring-0.2.4 → format_docstring-0.2.5}/tests/test_main_py.py +0 -0
  108. {format_docstring-0.2.4 → format_docstring-0.2.5}/tests/test_playground.py +0 -0
  109. {format_docstring-0.2.4 → format_docstring-0.2.5}/tox.ini +0 -0
@@ -208,3 +208,6 @@ __marimo__/
208
208
 
209
209
  # JetBrains IDEs
210
210
  .idea/
211
+
212
+ # VS Code
213
+ .vscode/
@@ -6,6 +6,14 @@ 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.2.5] - 2025-11-20
10
+
11
+ - Fixed
12
+ - A bug where `Generator[XXX, YYY, ZZZ]` in the return type annotation is not
13
+ parsed correctly (the Yields section should have been XXX)
14
+ - Full diff
15
+ - https://github.com/jsh9/format-docstring/compare/0.2.4...0.2.5
16
+
9
17
  ## [0.2.4] - 2025-10-27
10
18
 
11
19
  - Fixed
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: format-docstring
3
- Version: 0.2.4
3
+ Version: 0.2.5
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>
@@ -197,6 +197,7 @@ def wrap_docstring_numpy( # noqa: C901, PLR0915, TODO: https://github.com/jsh9/
197
197
 
198
198
  # Treat top-level lines as signatures
199
199
  if leading_indent is None or indent_length <= leading_indent:
200
+ is_yields_section = section_lower_case.startswith('yield')
200
201
  if not return_signature_style_determined:
201
202
  return_use_multiple_signatures = (
202
203
  _detect_multiple_return_signatures(
@@ -223,6 +224,12 @@ def wrap_docstring_numpy( # noqa: C901, PLR0915, TODO: https://github.com/jsh9/
223
224
  # Fallback to last component when docstring expects more
224
225
  desired_annotation = return_components[-1]
225
226
 
227
+ if is_yields_section:
228
+ desired_annotation = (
229
+ _unwrap_generator_annotation(desired_annotation)
230
+ or desired_annotation
231
+ )
232
+
226
233
  if desired_annotation is None:
227
234
  temp_out.append(line)
228
235
  i += 1
@@ -618,19 +625,6 @@ def _split_tuple_annotation(annotation: str | None) -> list[str] | None:
618
625
  except (SyntaxError, ValueError):
619
626
  return None
620
627
 
621
- def _name_of(node: ast.AST) -> str | None:
622
- if isinstance(node, ast.Name):
623
- return node.id
624
-
625
- if isinstance(node, ast.Attribute):
626
- base = _name_of(node.value)
627
- if base is None:
628
- return None
629
-
630
- return f'{base}.{node.attr}'
631
-
632
- return None
633
-
634
628
  if isinstance(expr, ast.Subscript):
635
629
  base_name = _name_of(expr.value)
636
630
  if base_name not in {'tuple', 'Tuple'}:
@@ -657,6 +651,63 @@ def _split_tuple_annotation(annotation: str | None) -> list[str] | None:
657
651
  return None
658
652
 
659
653
 
654
+ def _name_of(node: ast.AST) -> str | None:
655
+ """
656
+ Return the dotted name represented by ``node`` if possible.
657
+ """
658
+ if isinstance(node, ast.Name):
659
+ return node.id
660
+
661
+ if isinstance(node, ast.Attribute):
662
+ base = _name_of(node.value)
663
+ if base is None:
664
+ return None
665
+
666
+ return f'{base}.{node.attr}'
667
+
668
+ return None
669
+
670
+
671
+ def _unwrap_generator_annotation(annotation: str | None) -> str | None:
672
+ """
673
+ Return the first yield type when ``annotation`` is a Generator or
674
+ AsyncGenerator.
675
+
676
+ This is a small helper to keep ``Yields`` sections intuitive; Python
677
+ signatures often annotate generator functions as ``Generator[T, None,
678
+ None]`` but docstrings should spell out the yielded type ``T`` instead of
679
+ the whole container.
680
+ """
681
+ if annotation is None:
682
+ return None
683
+
684
+ try:
685
+ expr = ast.parse(annotation, mode='eval').body
686
+ except (SyntaxError, ValueError):
687
+ return None
688
+
689
+ if not isinstance(expr, ast.Subscript):
690
+ return None
691
+
692
+ base_name = _name_of(expr.value)
693
+ if base_name is None or base_name.split('.')[-1] not in {
694
+ 'Generator',
695
+ 'AsyncGenerator',
696
+ }:
697
+ return None
698
+
699
+ slice_node = expr.slice
700
+ if not isinstance(slice_node, ast.Tuple) or not slice_node.elts:
701
+ return None
702
+
703
+ first = slice_node.elts[0]
704
+ segment = ast.get_source_segment(annotation, first)
705
+ if segment is None:
706
+ segment = ast.unparse(first)
707
+
708
+ return segment.strip()
709
+
710
+
660
711
  def _detect_multiple_return_signatures(
661
712
  lines: list[str],
662
713
  start_idx: int,
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: format-docstring
3
- Version: 0.2.4
3
+ Version: 0.2.5
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>
@@ -4,7 +4,7 @@ requires = ["setuptools-scm[toml]>=6.2", "setuptools>=45"]
4
4
 
5
5
  [project]
6
6
  name = "format-docstring"
7
- version = "0.2.4"
7
+ version = "0.2.5"
8
8
  dependencies = [
9
9
  "click>=8.0",
10
10
  "jupyter-notebook-parser>=0.1.4",
@@ -51,6 +51,30 @@ def yield_custom_type_2() -> Iterator[tuple['MyType1', "MyType2"]]:
51
51
  yield 'value'
52
52
  yield 1
53
53
 
54
+
55
+ def yield_middle_non_none() -> Generator[int, str, None]:
56
+ """
57
+ Yield with send type.
58
+
59
+ Yields
60
+ ------
61
+ str
62
+ Should match first annotation element, not send type.
63
+ """
64
+ yield 1
65
+
66
+
67
+ def yield_last_non_none() -> Generator[int, None, str]:
68
+ """
69
+ Yield with return type.
70
+
71
+ Yields
72
+ ------
73
+ str
74
+ Should match first annotation element, not return type.
75
+ """
76
+ yield 1
77
+
54
78
  **********
55
79
  from collections.abc import Generator, Iterator
56
80
 
@@ -73,7 +97,7 @@ def yield_named() -> Generator[int, None, None]:
73
97
 
74
98
  Yields
75
99
  ------
76
- result : Generator[int, None, None]
100
+ result : int
77
101
  Should match annotation.
78
102
  """
79
103
  yield 1
@@ -101,3 +125,27 @@ def yield_custom_type_2() -> Iterator[tuple['MyType1', "MyType2"]]:
101
125
  """
102
126
  yield 'value'
103
127
  yield 1
128
+
129
+
130
+ def yield_middle_non_none() -> Generator[int, str, None]:
131
+ """
132
+ Yield with send type.
133
+
134
+ Yields
135
+ ------
136
+ int
137
+ Should match first annotation element, not send type.
138
+ """
139
+ yield 1
140
+
141
+
142
+ def yield_last_non_none() -> Generator[int, None, str]:
143
+ """
144
+ Yield with return type.
145
+
146
+ Yields
147
+ ------
148
+ int
149
+ Should match first annotation element, not return type.
150
+ """
151
+ yield 1