format-docstring 0.1.9__tar.gz → 0.2.0__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 (105) hide show
  1. {format_docstring-0.1.9 → format_docstring-0.2.0}/.pre-commit-config.yaml +21 -4
  2. {format_docstring-0.1.9 → format_docstring-0.2.0}/AGENTS.md +37 -0
  3. {format_docstring-0.1.9 → format_docstring-0.2.0}/CHANGELOG.md +11 -0
  4. {format_docstring-0.1.9 → format_docstring-0.2.0}/PKG-INFO +135 -10
  5. {format_docstring-0.1.9 → format_docstring-0.2.0}/README.md +134 -9
  6. {format_docstring-0.1.9 → format_docstring-0.2.0}/format_docstring/base_fixer.py +12 -2
  7. {format_docstring-0.1.9 → format_docstring-0.2.0}/format_docstring/docstring_rewriter.py +204 -10
  8. {format_docstring-0.1.9 → format_docstring-0.2.0}/format_docstring/line_wrap_google.py +5 -0
  9. {format_docstring-0.1.9 → format_docstring-0.2.0}/format_docstring/line_wrap_numpy.py +271 -3
  10. {format_docstring-0.1.9 → format_docstring-0.2.0}/format_docstring/line_wrap_utils.py +14 -8
  11. {format_docstring-0.1.9 → format_docstring-0.2.0}/format_docstring.egg-info/PKG-INFO +135 -10
  12. {format_docstring-0.1.9 → format_docstring-0.2.0}/format_docstring.egg-info/SOURCES.txt +2 -0
  13. {format_docstring-0.1.9 → format_docstring-0.2.0}/pyproject.toml +1 -1
  14. {format_docstring-0.1.9 → format_docstring-0.2.0}/tests/test_data/end_to_end/numpy/fix_rst_backticks.txt +1 -1
  15. format_docstring-0.2.0/tests/test_data/end_to_end/numpy/parameter_signature_sync.txt +197 -0
  16. format_docstring-0.2.0/tests/test_data/end_to_end/numpy/returns_signature_sync.txt +169 -0
  17. {format_docstring-0.1.9 → format_docstring-0.2.0}/tox.ini +15 -25
  18. {format_docstring-0.1.9 → format_docstring-0.2.0}/.github/workflows/python-package.yml +0 -0
  19. {format_docstring-0.1.9 → format_docstring-0.2.0}/.github/workflows/python-publish.yml +0 -0
  20. {format_docstring-0.1.9 → format_docstring-0.2.0}/.gitignore +0 -0
  21. {format_docstring-0.1.9 → format_docstring-0.2.0}/.pre-commit-hooks.yaml +0 -0
  22. {format_docstring-0.1.9 → format_docstring-0.2.0}/LICENSE +0 -0
  23. {format_docstring-0.1.9 → format_docstring-0.2.0}/format_docstring/__init__.py +0 -0
  24. {format_docstring-0.1.9 → format_docstring-0.2.0}/format_docstring/config.py +0 -0
  25. {format_docstring-0.1.9 → format_docstring-0.2.0}/format_docstring/main_jupyter.py +0 -0
  26. {format_docstring-0.1.9 → format_docstring-0.2.0}/format_docstring/main_py.py +0 -0
  27. {format_docstring-0.1.9 → format_docstring-0.2.0}/format_docstring.egg-info/dependency_links.txt +0 -0
  28. {format_docstring-0.1.9 → format_docstring-0.2.0}/format_docstring.egg-info/entry_points.txt +0 -0
  29. {format_docstring-0.1.9 → format_docstring-0.2.0}/format_docstring.egg-info/requires.txt +0 -0
  30. {format_docstring-0.1.9 → format_docstring-0.2.0}/format_docstring.egg-info/top_level.txt +0 -0
  31. {format_docstring-0.1.9 → format_docstring-0.2.0}/muff.toml +0 -0
  32. {format_docstring-0.1.9 → format_docstring-0.2.0}/requirements.dev +0 -0
  33. {format_docstring-0.1.9 → format_docstring-0.2.0}/setup.cfg +0 -0
  34. {format_docstring-0.1.9 → format_docstring-0.2.0}/tests/__init__.py +0 -0
  35. {format_docstring-0.1.9 → format_docstring-0.2.0}/tests/helpers.py +0 -0
  36. {format_docstring-0.1.9 → format_docstring-0.2.0}/tests/test_base_fixer.py +0 -0
  37. {format_docstring-0.1.9 → format_docstring-0.2.0}/tests/test_config.py +0 -0
  38. {format_docstring-0.1.9 → format_docstring-0.2.0}/tests/test_data/end_to_end/numpy/README.md +0 -0
  39. {format_docstring-0.1.9 → format_docstring-0.2.0}/tests/test_data/end_to_end/numpy/colon_spacing_fix.txt +0 -0
  40. {format_docstring-0.1.9 → format_docstring-0.2.0}/tests/test_data/end_to_end/numpy/contents_that_are_not_wrapped.txt +0 -0
  41. {format_docstring-0.1.9 → format_docstring-0.2.0}/tests/test_data/end_to_end/numpy/default_value_standardization.txt +0 -0
  42. {format_docstring-0.1.9 → format_docstring-0.2.0}/tests/test_data/end_to_end/numpy/empty_lines_are_respected.txt +0 -0
  43. {format_docstring-0.1.9 → format_docstring-0.2.0}/tests/test_data/end_to_end/numpy/examples_section.txt +0 -0
  44. {format_docstring-0.1.9 → format_docstring-0.2.0}/tests/test_data/end_to_end/numpy/existing_linebreaks_should_not_be_respected.txt +0 -0
  45. {format_docstring-0.1.9 → format_docstring-0.2.0}/tests/test_data/end_to_end/numpy/four_level_nested_classes.txt +0 -0
  46. {format_docstring-0.1.9 → format_docstring-0.2.0}/tests/test_data/end_to_end/numpy/indent_four_levels_16_spaces_width_10.txt +0 -0
  47. {format_docstring-0.1.9 → format_docstring-0.2.0}/tests/test_data/end_to_end/numpy/indent_misaligned_all.txt +0 -0
  48. {format_docstring-0.1.9 → format_docstring-0.2.0}/tests/test_data/end_to_end/numpy/indent_two_levels_8_spaces.txt +0 -0
  49. {format_docstring-0.1.9 → format_docstring-0.2.0}/tests/test_data/end_to_end/numpy/line_length_2.txt +0 -0
  50. {format_docstring-0.1.9 → format_docstring-0.2.0}/tests/test_data/end_to_end/numpy/mismatched_underlines.txt +0 -0
  51. {format_docstring-0.1.9 → format_docstring-0.2.0}/tests/test_data/end_to_end/numpy/mismatched_underlines_one_dash.txt +0 -0
  52. {format_docstring-0.1.9 → format_docstring-0.2.0}/tests/test_data/end_to_end/numpy/mismatched_underlines_two_dashes.txt +0 -0
  53. {format_docstring-0.1.9 → format_docstring-0.2.0}/tests/test_data/end_to_end/numpy/module_level_docstring.txt +0 -0
  54. {format_docstring-0.1.9 → format_docstring-0.2.0}/tests/test_data/end_to_end/numpy/new_lines_before_and_after.txt +0 -0
  55. {format_docstring-0.1.9 → format_docstring-0.2.0}/tests/test_data/end_to_end/numpy/no_format_docstring_comment.txt +0 -0
  56. {format_docstring-0.1.9 → format_docstring-0.2.0}/tests/test_data/end_to_end/numpy/param_signature_without_type.txt +0 -0
  57. {format_docstring-0.1.9 → format_docstring-0.2.0}/tests/test_data/end_to_end/numpy/parameters_returns_raises_wrapping.txt +0 -0
  58. {format_docstring-0.1.9 → format_docstring-0.2.0}/tests/test_data/end_to_end/numpy/returns_signature_and_description.txt +0 -0
  59. {format_docstring-0.1.9 → format_docstring-0.2.0}/tests/test_data/end_to_end/numpy/section_headings_with_colons.txt +0 -0
  60. {format_docstring-0.1.9 → format_docstring-0.2.0}/tests/test_data/end_to_end/numpy/section_title_fixed.txt +0 -0
  61. {format_docstring-0.1.9 → format_docstring-0.2.0}/tests/test_data/end_to_end/numpy/sections_notes_examples.txt +0 -0
  62. {format_docstring-0.1.9 → format_docstring-0.2.0}/tests/test_data/end_to_end/numpy/signature_line_is_not_wrapped.txt +0 -0
  63. {format_docstring-0.1.9 → format_docstring-0.2.0}/tests/test_data/end_to_end/numpy/single_line_docstring.txt +0 -0
  64. {format_docstring-0.1.9 → format_docstring-0.2.0}/tests/test_data/end_to_end/numpy/texts_are_rewrapped.txt +0 -0
  65. {format_docstring-0.1.9 → format_docstring-0.2.0}/tests/test_data/end_to_end/numpy/very_long_unbreakable_word.txt +0 -0
  66. {format_docstring-0.1.9 → format_docstring-0.2.0}/tests/test_data/integration_test/numpy/after.ipynb +0 -0
  67. {format_docstring-0.1.9 → format_docstring-0.2.0}/tests/test_data/integration_test/numpy/after.py +0 -0
  68. {format_docstring-0.1.9 → format_docstring-0.2.0}/tests/test_data/integration_test/numpy/after_50.ipynb +0 -0
  69. {format_docstring-0.1.9 → format_docstring-0.2.0}/tests/test_data/integration_test/numpy/after_50.py +0 -0
  70. {format_docstring-0.1.9 → format_docstring-0.2.0}/tests/test_data/integration_test/numpy/before.ipynb +0 -0
  71. {format_docstring-0.1.9 → format_docstring-0.2.0}/tests/test_data/integration_test/numpy/before.py +0 -0
  72. {format_docstring-0.1.9 → format_docstring-0.2.0}/tests/test_data/jupyter/before.ipynb +0 -0
  73. {format_docstring-0.1.9 → format_docstring-0.2.0}/tests/test_data/jupyter/verbose_before.ipynb +0 -0
  74. {format_docstring-0.1.9 → format_docstring-0.2.0}/tests/test_data/line_wrap/numpy/README.md +0 -0
  75. {format_docstring-0.1.9 → format_docstring-0.2.0}/tests/test_data/line_wrap/numpy/colon_spacing_fix.txt +0 -0
  76. {format_docstring-0.1.9 → format_docstring-0.2.0}/tests/test_data/line_wrap/numpy/contents_that_are_not_wrapped.txt +0 -0
  77. {format_docstring-0.1.9 → format_docstring-0.2.0}/tests/test_data/line_wrap/numpy/default_value_standardization.txt +0 -0
  78. {format_docstring-0.1.9 → format_docstring-0.2.0}/tests/test_data/line_wrap/numpy/empty_lines_are_respected.txt +0 -0
  79. {format_docstring-0.1.9 → format_docstring-0.2.0}/tests/test_data/line_wrap/numpy/examples_section.txt +0 -0
  80. {format_docstring-0.1.9 → format_docstring-0.2.0}/tests/test_data/line_wrap/numpy/existing_linebreaks_should_not_be_respected.txt +0 -0
  81. {format_docstring-0.1.9 → format_docstring-0.2.0}/tests/test_data/line_wrap/numpy/fix_rst_backticks.txt +0 -0
  82. {format_docstring-0.1.9 → format_docstring-0.2.0}/tests/test_data/line_wrap/numpy/indent_four_levels_16_spaces_width_10.txt +0 -0
  83. {format_docstring-0.1.9 → format_docstring-0.2.0}/tests/test_data/line_wrap/numpy/indent_two_levels_8_spaces.txt +0 -0
  84. {format_docstring-0.1.9 → format_docstring-0.2.0}/tests/test_data/line_wrap/numpy/line_length_2.txt +0 -0
  85. {format_docstring-0.1.9 → format_docstring-0.2.0}/tests/test_data/line_wrap/numpy/mismatched_underlines.txt +0 -0
  86. {format_docstring-0.1.9 → format_docstring-0.2.0}/tests/test_data/line_wrap/numpy/mismatched_underlines_one_dash.txt +0 -0
  87. {format_docstring-0.1.9 → format_docstring-0.2.0}/tests/test_data/line_wrap/numpy/mismatched_underlines_two_dashes.txt +0 -0
  88. {format_docstring-0.1.9 → format_docstring-0.2.0}/tests/test_data/line_wrap/numpy/module_level_docstring.txt +0 -0
  89. {format_docstring-0.1.9 → format_docstring-0.2.0}/tests/test_data/line_wrap/numpy/param_signature_without_type.txt +0 -0
  90. {format_docstring-0.1.9 → format_docstring-0.2.0}/tests/test_data/line_wrap/numpy/parameters_returns_raises_wrapping.txt +0 -0
  91. {format_docstring-0.1.9 → format_docstring-0.2.0}/tests/test_data/line_wrap/numpy/returns_signature_and_description.txt +0 -0
  92. {format_docstring-0.1.9 → format_docstring-0.2.0}/tests/test_data/line_wrap/numpy/section_headings_with_colons.txt +0 -0
  93. {format_docstring-0.1.9 → format_docstring-0.2.0}/tests/test_data/line_wrap/numpy/section_title_fixed.txt +0 -0
  94. {format_docstring-0.1.9 → format_docstring-0.2.0}/tests/test_data/line_wrap/numpy/sections_notes_examples.txt +0 -0
  95. {format_docstring-0.1.9 → format_docstring-0.2.0}/tests/test_data/line_wrap/numpy/signature_line_is_not_wrapped.txt +0 -0
  96. {format_docstring-0.1.9 → format_docstring-0.2.0}/tests/test_data/line_wrap/numpy/texts_are_rewrapped.txt +0 -0
  97. {format_docstring-0.1.9 → format_docstring-0.2.0}/tests/test_data/line_wrap/numpy/very_long_unbreakable_word.txt +0 -0
  98. {format_docstring-0.1.9 → format_docstring-0.2.0}/tests/test_data/playground.py +0 -0
  99. {format_docstring-0.1.9 → format_docstring-0.2.0}/tests/test_docstring_rewriter.py +0 -0
  100. {format_docstring-0.1.9 → format_docstring-0.2.0}/tests/test_line_wrap_google.py +0 -0
  101. {format_docstring-0.1.9 → format_docstring-0.2.0}/tests/test_line_wrap_numpy.py +0 -0
  102. {format_docstring-0.1.9 → format_docstring-0.2.0}/tests/test_line_wrap_utils.py +0 -0
  103. {format_docstring-0.1.9 → format_docstring-0.2.0}/tests/test_main_jupyter.py +0 -0
  104. {format_docstring-0.1.9 → format_docstring-0.2.0}/tests/test_main_py.py +0 -0
  105. {format_docstring-0.1.9 → format_docstring-0.2.0}/tests/test_playground.py +0 -0
@@ -5,12 +5,19 @@ repos:
5
5
  hooks:
6
6
  - id: trailing-whitespace
7
7
  - id: end-of-file-fixer
8
+ exclude: \.json$|\.ipynb$
8
9
  - id: debug-statements
9
10
  - id: double-quote-string-fixer
10
11
  - id: requirements-txt-fixer
11
- - id: pretty-format-json
12
- args: [--no-ensure-ascii, --indent=4, --no-sort-keys]
13
12
  exclude: \.ipynb$
13
+ - id: check-added-large-files
14
+ args: [--maxkb=1000]
15
+ - id: check-toml
16
+ - id: check-yaml
17
+ - id: name-tests-test
18
+ args: [--pytest-test-first]
19
+ exclude: ^tests/test_data/|^tests/helpers\.py$
20
+ - id: check-merge-conflict
14
21
  - repo: https://github.com/asottile/pyupgrade
15
22
  rev: v3.20.0
16
23
  hooks:
@@ -31,11 +38,21 @@ repos:
31
38
  hooks:
32
39
  - id: yamlfix
33
40
  - repo: https://github.com/hukkin/mdformat
34
- rev: 0.7.22
41
+ rev: 1.0.0
35
42
  hooks:
36
43
  - id: mdformat
37
44
  args: [--wrap, '79', --number]
38
- additional_dependencies: [mdformat-tables]
45
+ additional_dependencies: [mdformat-gfm]
46
+ - repo: https://github.com/jsh9/format-json
47
+ rev: 0.1.2
48
+ hooks:
49
+ - id: format-json
50
+ args:
51
+ - --autofix
52
+ - --no-ensure-ascii
53
+ - --indent=4
54
+ - --no-sort-keys
55
+ - --no-eof-newline
39
56
  - repo: https://github.com/jsh9/markdown-toc-creator
40
57
  rev: 0.0.11
41
58
  hooks:
@@ -38,8 +38,17 @@ oriented before making changes.
38
38
  - `docstring_rewriter.fix_src` parses with `ast.parse`, collects docstring
39
39
  literals, and rewrites source slices using absolute offsets from
40
40
  `calc_line_starts`; this avoids `ast.unparse` and keeps comments/spacing.
41
+ - For functions, `_collect_param_metadata` records signature annotations and
42
+ default values so NumPy `Parameters` signatures in docstrings are
43
+ resynchronised with the real function definition. Defaulted parameters omit
44
+ redundant `, optional`, and forward references keep their original quoting.
45
+ - Return annotations are likewise projected into `Returns`/`Yields` sections,
46
+ mirroring tuple element splits when the docstring already enumerates them.
41
47
  - Wrapping honors NumPy section heuristics, rST constructs, code fences,
42
48
  `Examples` prompts, and literal blocks introduced by `::`.
49
+ - `_normalize_signature_segment` flattens multiline annotations via
50
+ `ast.unparse` but uses token-level replay to preserve the author's quoting
51
+ style for forward references and string defaults.
43
52
  - CLI exposes `--docstring-style`, but the Python entry-point currently raises
44
53
  if a non-NumPy style is requested; Jupyter flow passes style through
45
54
  unchanged.
@@ -91,3 +100,31 @@ oriented before making changes.
91
100
  - Keep docstring style tests conservative: avoid mutating non-docstring
92
101
  content, and add regression cases whenever handling around literal sections
93
102
  or tables changes.
103
+
104
+ ## What is a "signature line"?
105
+
106
+ They are the lines in the docstring where input and return args are defined,
107
+ for example, in this docstring:
108
+
109
+ ```python
110
+ """
111
+ Do something
112
+
113
+ Parameters
114
+ ----------
115
+ arg1 : str
116
+ Arg 1
117
+ arg2 : int = 2
118
+ Arg 2
119
+
120
+ Returns
121
+ -------
122
+ dict[str, str]
123
+ The mapping
124
+ ```
125
+
126
+ Signature lines are:
127
+
128
+ - arg1 : str
129
+ - arg2 : int = 2
130
+ - dict[str, str]
@@ -6,6 +6,15 @@ 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.0] - 2025-10-20
10
+
11
+ - Added
12
+ - AST-driven synchronization of NumPy `Parameters` and `Returns` signature
13
+ lines with the function signature, including tuple element expansion for
14
+ multi-line return blocks
15
+ - Full diff
16
+ - https://github.com/jsh9/format-docstring/compare/0.1.9...0.2.0
17
+
9
18
  ## [0.1.9] - 2025-10-16
10
19
 
11
20
  - Added
@@ -17,6 +26,8 @@ adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
17
26
  - Changed
18
27
  - Added "self format" pre-commit hook to format docstrings within this repo
19
28
  with its own formatting logic
29
+ - Full diff
30
+ - https://github.com/jsh9/format-docstring/compare/0.1.8...0.1.9
20
31
 
21
32
  ## [0.1.8] - 2025-10-14
22
33
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: format-docstring
3
- Version: 0.1.9
3
+ Version: 0.2.0
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>
@@ -34,6 +34,8 @@ Dynamic: license-file
34
34
 
35
35
  A Python formatter to automatically format numpy-style docstrings.
36
36
 
37
+ ______________________________________________________________________
38
+
37
39
  **Table of Contents:**
38
40
 
39
41
  <!--TOC-->
@@ -45,6 +47,7 @@ A Python formatter to automatically format numpy-style docstrings.
45
47
  - [2.3. Minor typos can be automatically fixed](#23-minor-typos-can-be-automatically-fixed)
46
48
  - [2.4. Default value declarations are standardized](#24-default-value-declarations-are-standardized)
47
49
  - [2.5. Single backticks are converted to double backticks (rST syntax)](#25-single-backticks-are-converted-to-double-backticks-rst-syntax)
50
+ - [2.6. Docstring parameters and returns stay in sync with signatures](#26-docstring-parameters-and-returns-stay-in-sync-with-signatures)
48
51
  - [3. Installation](#3-installation)
49
52
  - [4. Usage](#4-usage)
50
53
  - [4.1. Command Line Interface](#41-command-line-interface)
@@ -54,24 +57,28 @@ A Python formatter to automatically format numpy-style docstrings.
54
57
  - [5.1. Command-Line Options](#51-command-line-options)
55
58
  - [5.2. Usage Examples](#52-usage-examples)
56
59
  - [5.3. `pyproject.toml` Configuration](#53-pyprojecttoml-configuration)
60
+ - [6. Caveat](#6-caveat)
57
61
 
58
62
  <!--TOC-->
59
63
 
64
+ ______________________________________________________________________
65
+
60
66
  ## 1. Overview
61
67
 
62
68
  `format-docstring` is a tool that automatically formats and wraps docstring
63
69
  content in Python files and Jupyter notebooks.
64
70
 
65
- Compared with [`docformatter`](https://github.com/PyCQA/docformatter) and
66
- [`pydocstringformatter`](https://github.com/DanielNoord/pydocstringformatter),
67
- this tool (`format-docstring`) goes further by intelligently wrapping docstring
68
- contents, fixing common typos, etc.
71
+ Baseline reflow corresponds to the common docstring cleanups offered by
72
+ general-purpose formatters: splitting one-line docstrings into the canonical
73
+ multi-line layout (triple quotes, blank line, summary), normalizing
74
+ indentation, and wrapping text at a fixed column width without applying extra
75
+ heuristics.
69
76
 
70
- The formatting that would be done by
71
- [docformatter](https://github.com/PyCQA/docformatter) and
72
- [pydocstringformatter](https://github.com/DanielNoord/pydocstringformatter) can
73
- be readily handled by [Ruff](https://github.com/astral-sh/ruff) or
74
- [Black](https://github.com/psf/black).
77
+ | Feature | `format-docstring` | [docformatter] | [pydocstringformatter] | [Ruff] | [Black] |
78
+ | ----------------------------------------- | ------------------ | -------------- | ---------------------- | ------ | ------- |
79
+ | Docstring wrapping | ✅ | ❌ | ❌ | ❌ | ❌ |
80
+ | Compatible with line length linter (E501) | ✅ | ❌ | ❌ | N/A | N/A |
81
+ | Fixes common docstring typos | ✅ | ❌ | ❌ | ❌ | ❌ |
75
82
 
76
83
  ## 2. Before vs After Examples
77
84
 
@@ -187,6 +194,25 @@ def mu_function():
187
194
  pass
188
195
  ```
189
196
 
197
+ or, Google-style section headers can be fixed:
198
+
199
+ ```diff
200
+ def my_function():
201
+ """
202
+ My function
203
+
204
+ - Args:
205
+ - ----
206
+ + Parameters
207
+ + ----------
208
+ arg1 : str
209
+ Arg 1
210
+
211
+ ...
212
+ """
213
+ pass
214
+ ```
215
+
190
216
  ### 2.4. Default value declarations are standardized
191
217
 
192
218
  ```diff
@@ -230,9 +256,94 @@ def process_data(data):
230
256
  - Processed data with key `result`.
231
257
  + Processed data with key ``result``.
232
258
  """
259
+ ```
260
+
261
+ ### 2.6. Docstring parameters and returns stay in sync with signatures
262
+
263
+ ```diff
264
+ from typing import List, Optional
265
+
266
+
267
+ def create_user(
268
+ user: Optional[str] = None,
269
+ roles: List["Role"] | None = None,
270
+ retries: int = 0,
271
+ serializer: "Serializer" | None = None,
272
+ something_else: tuple[int, ...] = (
273
+ "1",
274
+ '2',
275
+ 3,
276
+ 4,
277
+ 5,
278
+ 6,
279
+ 7,
280
+ 8,
281
+ 9,
282
+ 10,
283
+ 11,
284
+ 12,
285
+ ),
286
+ ) -> None:
287
+ """
288
+ Parameters
289
+ ----------
290
+ - user : str
291
+ + user : Optional[str], default=None
292
+ Login name.
293
+ - roles : list
294
+ + roles : List["Role"] | None, default=None
295
+ Assigned roles.
296
+ - retries : int
297
+ + retries : int, default=0
298
+ Number of retry attempts.
299
+ - serializer : Serializer, optional
300
+ + serializer : "Serializer" | None, default=None
301
+ Custom serializer instance.
302
+ - something_else : tuple[int, ...]
303
+ + something_else : tuple[int, ...], default=("1", '2', 3, 4, 5, 6, 7, 8, 9, 10, 11, 12)
304
+ """
233
305
  pass
234
306
  ```
235
307
 
308
+ And return type hint:
309
+
310
+ ```diff
311
+ def build_mapping() -> dict[str, str]:
312
+ """
313
+ Returns
314
+ -------
315
+ - str
316
+ + dict[str, str]
317
+ Mapping of values.
318
+ """
319
+ ```
320
+
321
+ For tuple return annotations, tuple elements are split across multiple
322
+ signature lines only when the docstring already adopted that layout:
323
+
324
+ ```diff
325
+ def compute_values() -> tuple[int, str, list[str]]:
326
+ """
327
+ Returns
328
+ -------
329
+ - float
330
+ + int
331
+ First element.
332
+ - str
333
+ + str
334
+ Second element.
335
+ - List[str]
336
+ + list[str]
337
+ Third element.
338
+ """
339
+ ```
340
+
341
+ Annotations and defaults are extracted from the actual function signature, so
342
+ docstring signature lines reflect the ground truth. Defaulted parameters omit
343
+ redundant `, optional`, forward references keep their original quoting, and
344
+ return signatures track tuple splitting conventions already present in the
345
+ docstring.
346
+
236
347
  ## 3. Installation
237
348
 
238
349
  ```bash
@@ -367,3 +478,17 @@ verbose = "default" # or "diff" to print unified diffs
367
478
 
368
479
  The tool searches for `pyproject.toml` starting from the target file/directory
369
480
  and walking up the parent directories until one is found.
481
+
482
+ ## 6. Caveat
483
+
484
+ This tool assumes the docstrings are written in **mostly** the correct format,
485
+ because it needs those formatting cues (such as section headers and `------`)
486
+ to parse docstrings.
487
+
488
+ If the docstrings are far from perfectly formatted, it's recommended that you
489
+ use AI coding assistants to rewrite the docstrings first.
490
+
491
+ [black]: https://github.com/psf/black
492
+ [docformatter]: https://github.com/PyCQA/docformatter
493
+ [pydocstringformatter]: https://github.com/DanielNoord/pydocstringformatter
494
+ [ruff]: https://github.com/astral-sh/ruff
@@ -2,6 +2,8 @@
2
2
 
3
3
  A Python formatter to automatically format numpy-style docstrings.
4
4
 
5
+ ______________________________________________________________________
6
+
5
7
  **Table of Contents:**
6
8
 
7
9
  <!--TOC-->
@@ -13,6 +15,7 @@ A Python formatter to automatically format numpy-style docstrings.
13
15
  - [2.3. Minor typos can be automatically fixed](#23-minor-typos-can-be-automatically-fixed)
14
16
  - [2.4. Default value declarations are standardized](#24-default-value-declarations-are-standardized)
15
17
  - [2.5. Single backticks are converted to double backticks (rST syntax)](#25-single-backticks-are-converted-to-double-backticks-rst-syntax)
18
+ - [2.6. Docstring parameters and returns stay in sync with signatures](#26-docstring-parameters-and-returns-stay-in-sync-with-signatures)
16
19
  - [3. Installation](#3-installation)
17
20
  - [4. Usage](#4-usage)
18
21
  - [4.1. Command Line Interface](#41-command-line-interface)
@@ -22,24 +25,28 @@ A Python formatter to automatically format numpy-style docstrings.
22
25
  - [5.1. Command-Line Options](#51-command-line-options)
23
26
  - [5.2. Usage Examples](#52-usage-examples)
24
27
  - [5.3. `pyproject.toml` Configuration](#53-pyprojecttoml-configuration)
28
+ - [6. Caveat](#6-caveat)
25
29
 
26
30
  <!--TOC-->
27
31
 
32
+ ______________________________________________________________________
33
+
28
34
  ## 1. Overview
29
35
 
30
36
  `format-docstring` is a tool that automatically formats and wraps docstring
31
37
  content in Python files and Jupyter notebooks.
32
38
 
33
- Compared with [`docformatter`](https://github.com/PyCQA/docformatter) and
34
- [`pydocstringformatter`](https://github.com/DanielNoord/pydocstringformatter),
35
- this tool (`format-docstring`) goes further by intelligently wrapping docstring
36
- contents, fixing common typos, etc.
39
+ Baseline reflow corresponds to the common docstring cleanups offered by
40
+ general-purpose formatters: splitting one-line docstrings into the canonical
41
+ multi-line layout (triple quotes, blank line, summary), normalizing
42
+ indentation, and wrapping text at a fixed column width without applying extra
43
+ heuristics.
37
44
 
38
- The formatting that would be done by
39
- [docformatter](https://github.com/PyCQA/docformatter) and
40
- [pydocstringformatter](https://github.com/DanielNoord/pydocstringformatter) can
41
- be readily handled by [Ruff](https://github.com/astral-sh/ruff) or
42
- [Black](https://github.com/psf/black).
45
+ | Feature | `format-docstring` | [docformatter] | [pydocstringformatter] | [Ruff] | [Black] |
46
+ | ----------------------------------------- | ------------------ | -------------- | ---------------------- | ------ | ------- |
47
+ | Docstring wrapping | ✅ | ❌ | ❌ | ❌ | ❌ |
48
+ | Compatible with line length linter (E501) | ✅ | ❌ | ❌ | N/A | N/A |
49
+ | Fixes common docstring typos | ✅ | ❌ | ❌ | ❌ | ❌ |
43
50
 
44
51
  ## 2. Before vs After Examples
45
52
 
@@ -155,6 +162,25 @@ def mu_function():
155
162
  pass
156
163
  ```
157
164
 
165
+ or, Google-style section headers can be fixed:
166
+
167
+ ```diff
168
+ def my_function():
169
+ """
170
+ My function
171
+
172
+ - Args:
173
+ - ----
174
+ + Parameters
175
+ + ----------
176
+ arg1 : str
177
+ Arg 1
178
+
179
+ ...
180
+ """
181
+ pass
182
+ ```
183
+
158
184
  ### 2.4. Default value declarations are standardized
159
185
 
160
186
  ```diff
@@ -198,9 +224,94 @@ def process_data(data):
198
224
  - Processed data with key `result`.
199
225
  + Processed data with key ``result``.
200
226
  """
227
+ ```
228
+
229
+ ### 2.6. Docstring parameters and returns stay in sync with signatures
230
+
231
+ ```diff
232
+ from typing import List, Optional
233
+
234
+
235
+ def create_user(
236
+ user: Optional[str] = None,
237
+ roles: List["Role"] | None = None,
238
+ retries: int = 0,
239
+ serializer: "Serializer" | None = None,
240
+ something_else: tuple[int, ...] = (
241
+ "1",
242
+ '2',
243
+ 3,
244
+ 4,
245
+ 5,
246
+ 6,
247
+ 7,
248
+ 8,
249
+ 9,
250
+ 10,
251
+ 11,
252
+ 12,
253
+ ),
254
+ ) -> None:
255
+ """
256
+ Parameters
257
+ ----------
258
+ - user : str
259
+ + user : Optional[str], default=None
260
+ Login name.
261
+ - roles : list
262
+ + roles : List["Role"] | None, default=None
263
+ Assigned roles.
264
+ - retries : int
265
+ + retries : int, default=0
266
+ Number of retry attempts.
267
+ - serializer : Serializer, optional
268
+ + serializer : "Serializer" | None, default=None
269
+ Custom serializer instance.
270
+ - something_else : tuple[int, ...]
271
+ + something_else : tuple[int, ...], default=("1", '2', 3, 4, 5, 6, 7, 8, 9, 10, 11, 12)
272
+ """
201
273
  pass
202
274
  ```
203
275
 
276
+ And return type hint:
277
+
278
+ ```diff
279
+ def build_mapping() -> dict[str, str]:
280
+ """
281
+ Returns
282
+ -------
283
+ - str
284
+ + dict[str, str]
285
+ Mapping of values.
286
+ """
287
+ ```
288
+
289
+ For tuple return annotations, tuple elements are split across multiple
290
+ signature lines only when the docstring already adopted that layout:
291
+
292
+ ```diff
293
+ def compute_values() -> tuple[int, str, list[str]]:
294
+ """
295
+ Returns
296
+ -------
297
+ - float
298
+ + int
299
+ First element.
300
+ - str
301
+ + str
302
+ Second element.
303
+ - List[str]
304
+ + list[str]
305
+ Third element.
306
+ """
307
+ ```
308
+
309
+ Annotations and defaults are extracted from the actual function signature, so
310
+ docstring signature lines reflect the ground truth. Defaulted parameters omit
311
+ redundant `, optional`, forward references keep their original quoting, and
312
+ return signatures track tuple splitting conventions already present in the
313
+ docstring.
314
+
204
315
  ## 3. Installation
205
316
 
206
317
  ```bash
@@ -335,3 +446,17 @@ verbose = "default" # or "diff" to print unified diffs
335
446
 
336
447
  The tool searches for `pyproject.toml` starting from the target file/directory
337
448
  and walking up the parent directories until one is found.
449
+
450
+ ## 6. Caveat
451
+
452
+ This tool assumes the docstrings are written in **mostly** the correct format,
453
+ because it needs those formatting cues (such as section headers and `------`)
454
+ to parse docstrings.
455
+
456
+ If the docstrings are far from perfectly formatted, it's recommended that you
457
+ use AI coding assistants to rewrite the docstrings first.
458
+
459
+ [black]: https://github.com/psf/black
460
+ [docformatter]: https://github.com/PyCQA/docformatter
461
+ [pydocstringformatter]: https://github.com/DanielNoord/pydocstringformatter
462
+ [ruff]: https://github.com/astral-sh/ruff
@@ -8,7 +8,18 @@ from typing import Any
8
8
 
9
9
 
10
10
  class BaseFixer:
11
- """Base class for fixing code formatting issues."""
11
+ r"""
12
+ Base class for fixing code formatting issues.
13
+
14
+ Parameters
15
+ ----------
16
+ path : str
17
+ Target file or directory to process.
18
+ exclude_pattern : str, default='\.git|\.tox|\.pytest_cache'
19
+ Regular expression describing paths to skip.
20
+ verbose : str, default='default'
21
+ Verbosity mode; ``'diff'`` prints unified diffs for rewritten files.
22
+ """
12
23
 
13
24
  def __init__(
14
25
  self,
@@ -16,7 +27,6 @@ class BaseFixer:
16
27
  exclude_pattern: str = r'\.git|\.tox|\.pytest_cache',
17
28
  verbose: str = 'default',
18
29
  ) -> None:
19
- """Initialize the fixer with a path and optional exclude pattern."""
20
30
  self.path = path
21
31
  self.exclude_pattern = exclude_pattern
22
32
  self.verbose = verbose