format-docstring 0.1.8__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 (110) hide show
  1. format_docstring-0.2.0/.pre-commit-config.yaml +83 -0
  2. format_docstring-0.2.0/AGENTS.md +130 -0
  3. {format_docstring-0.1.8 → format_docstring-0.2.0}/CHANGELOG.md +23 -0
  4. {format_docstring-0.1.8 → format_docstring-0.2.0}/PKG-INFO +156 -11
  5. {format_docstring-0.1.8 → format_docstring-0.2.0}/README.md +155 -9
  6. {format_docstring-0.1.8 → format_docstring-0.2.0}/format_docstring/base_fixer.py +38 -4
  7. format_docstring-0.2.0/format_docstring/docstring_rewriter.py +577 -0
  8. {format_docstring-0.1.8 → format_docstring-0.2.0}/format_docstring/line_wrap_google.py +5 -0
  9. {format_docstring-0.1.8 → format_docstring-0.2.0}/format_docstring/line_wrap_numpy.py +318 -27
  10. {format_docstring-0.1.8 → format_docstring-0.2.0}/format_docstring/line_wrap_utils.py +76 -40
  11. {format_docstring-0.1.8 → format_docstring-0.2.0}/format_docstring/main_jupyter.py +21 -6
  12. {format_docstring-0.1.8 → format_docstring-0.2.0}/format_docstring/main_py.py +16 -1
  13. {format_docstring-0.1.8 → format_docstring-0.2.0}/format_docstring.egg-info/PKG-INFO +156 -11
  14. {format_docstring-0.1.8 → format_docstring-0.2.0}/format_docstring.egg-info/SOURCES.txt +9 -1
  15. {format_docstring-0.1.8 → format_docstring-0.2.0}/format_docstring.egg-info/requires.txt +0 -1
  16. {format_docstring-0.1.8 → format_docstring-0.2.0}/muff.toml +1 -1
  17. {format_docstring-0.1.8 → format_docstring-0.2.0}/pyproject.toml +1 -2
  18. {format_docstring-0.1.8 → format_docstring-0.2.0}/tests/helpers.py +2 -1
  19. format_docstring-0.2.0/tests/test_base_fixer.py +47 -0
  20. {format_docstring-0.1.8 → format_docstring-0.2.0}/tests/test_config.py +2 -0
  21. {format_docstring-0.1.8 → format_docstring-0.2.0}/tests/test_data/end_to_end/numpy/fix_rst_backticks.txt +1 -1
  22. format_docstring-0.2.0/tests/test_data/end_to_end/numpy/no_format_docstring_comment.txt +54 -0
  23. format_docstring-0.2.0/tests/test_data/end_to_end/numpy/parameter_signature_sync.txt +197 -0
  24. format_docstring-0.2.0/tests/test_data/end_to_end/numpy/returns_signature_sync.txt +169 -0
  25. format_docstring-0.2.0/tests/test_data/end_to_end/numpy/section_headings_with_colons.txt +68 -0
  26. format_docstring-0.2.0/tests/test_data/jupyter/before.ipynb +28 -0
  27. format_docstring-0.2.0/tests/test_data/jupyter/verbose_before.ipynb +28 -0
  28. format_docstring-0.2.0/tests/test_data/line_wrap/numpy/section_headings_with_colons.txt +60 -0
  29. {format_docstring-0.1.8 → format_docstring-0.2.0}/tests/test_docstring_rewriter.py +5 -0
  30. {format_docstring-0.1.8 → format_docstring-0.2.0}/tests/test_line_wrap_numpy.py +3 -1
  31. format_docstring-0.2.0/tests/test_main_jupyter.py +90 -0
  32. format_docstring-0.2.0/tests/test_main_py.py +88 -0
  33. {format_docstring-0.1.8 → format_docstring-0.2.0}/tox.ini +15 -25
  34. format_docstring-0.1.8/.pre-commit-config.yaml +0 -42
  35. format_docstring-0.1.8/CLAUDE.md +0 -151
  36. format_docstring-0.1.8/format_docstring/docstring_rewriter.py +0 -341
  37. format_docstring-0.1.8/tests/test_main_jupyter.py +0 -45
  38. format_docstring-0.1.8/tests/test_main_py.py +0 -42
  39. {format_docstring-0.1.8 → format_docstring-0.2.0}/.github/workflows/python-package.yml +0 -0
  40. {format_docstring-0.1.8 → format_docstring-0.2.0}/.github/workflows/python-publish.yml +0 -0
  41. {format_docstring-0.1.8 → format_docstring-0.2.0}/.gitignore +0 -0
  42. {format_docstring-0.1.8 → format_docstring-0.2.0}/.pre-commit-hooks.yaml +0 -0
  43. {format_docstring-0.1.8 → format_docstring-0.2.0}/LICENSE +0 -0
  44. {format_docstring-0.1.8 → format_docstring-0.2.0}/format_docstring/__init__.py +0 -0
  45. {format_docstring-0.1.8 → format_docstring-0.2.0}/format_docstring/config.py +0 -0
  46. {format_docstring-0.1.8 → format_docstring-0.2.0}/format_docstring.egg-info/dependency_links.txt +0 -0
  47. {format_docstring-0.1.8 → format_docstring-0.2.0}/format_docstring.egg-info/entry_points.txt +0 -0
  48. {format_docstring-0.1.8 → format_docstring-0.2.0}/format_docstring.egg-info/top_level.txt +0 -0
  49. {format_docstring-0.1.8 → format_docstring-0.2.0}/requirements.dev +0 -0
  50. {format_docstring-0.1.8 → format_docstring-0.2.0}/setup.cfg +0 -0
  51. {format_docstring-0.1.8 → format_docstring-0.2.0}/tests/__init__.py +0 -0
  52. {format_docstring-0.1.8 → format_docstring-0.2.0}/tests/test_data/end_to_end/numpy/README.md +0 -0
  53. {format_docstring-0.1.8 → format_docstring-0.2.0}/tests/test_data/end_to_end/numpy/colon_spacing_fix.txt +0 -0
  54. {format_docstring-0.1.8 → format_docstring-0.2.0}/tests/test_data/end_to_end/numpy/contents_that_are_not_wrapped.txt +0 -0
  55. {format_docstring-0.1.8 → format_docstring-0.2.0}/tests/test_data/end_to_end/numpy/default_value_standardization.txt +0 -0
  56. {format_docstring-0.1.8 → format_docstring-0.2.0}/tests/test_data/end_to_end/numpy/empty_lines_are_respected.txt +0 -0
  57. {format_docstring-0.1.8 → format_docstring-0.2.0}/tests/test_data/end_to_end/numpy/examples_section.txt +0 -0
  58. {format_docstring-0.1.8 → format_docstring-0.2.0}/tests/test_data/end_to_end/numpy/existing_linebreaks_should_not_be_respected.txt +0 -0
  59. {format_docstring-0.1.8 → format_docstring-0.2.0}/tests/test_data/end_to_end/numpy/four_level_nested_classes.txt +0 -0
  60. {format_docstring-0.1.8 → format_docstring-0.2.0}/tests/test_data/end_to_end/numpy/indent_four_levels_16_spaces_width_10.txt +0 -0
  61. {format_docstring-0.1.8 → format_docstring-0.2.0}/tests/test_data/end_to_end/numpy/indent_misaligned_all.txt +0 -0
  62. {format_docstring-0.1.8 → format_docstring-0.2.0}/tests/test_data/end_to_end/numpy/indent_two_levels_8_spaces.txt +0 -0
  63. {format_docstring-0.1.8 → format_docstring-0.2.0}/tests/test_data/end_to_end/numpy/line_length_2.txt +0 -0
  64. {format_docstring-0.1.8 → format_docstring-0.2.0}/tests/test_data/end_to_end/numpy/mismatched_underlines.txt +0 -0
  65. {format_docstring-0.1.8 → format_docstring-0.2.0}/tests/test_data/end_to_end/numpy/mismatched_underlines_one_dash.txt +0 -0
  66. {format_docstring-0.1.8 → format_docstring-0.2.0}/tests/test_data/end_to_end/numpy/mismatched_underlines_two_dashes.txt +0 -0
  67. {format_docstring-0.1.8 → format_docstring-0.2.0}/tests/test_data/end_to_end/numpy/module_level_docstring.txt +0 -0
  68. {format_docstring-0.1.8 → format_docstring-0.2.0}/tests/test_data/end_to_end/numpy/new_lines_before_and_after.txt +0 -0
  69. {format_docstring-0.1.8 → format_docstring-0.2.0}/tests/test_data/end_to_end/numpy/param_signature_without_type.txt +0 -0
  70. {format_docstring-0.1.8 → format_docstring-0.2.0}/tests/test_data/end_to_end/numpy/parameters_returns_raises_wrapping.txt +0 -0
  71. {format_docstring-0.1.8 → format_docstring-0.2.0}/tests/test_data/end_to_end/numpy/returns_signature_and_description.txt +0 -0
  72. {format_docstring-0.1.8 → format_docstring-0.2.0}/tests/test_data/end_to_end/numpy/section_title_fixed.txt +0 -0
  73. {format_docstring-0.1.8 → format_docstring-0.2.0}/tests/test_data/end_to_end/numpy/sections_notes_examples.txt +0 -0
  74. {format_docstring-0.1.8 → format_docstring-0.2.0}/tests/test_data/end_to_end/numpy/signature_line_is_not_wrapped.txt +0 -0
  75. {format_docstring-0.1.8 → format_docstring-0.2.0}/tests/test_data/end_to_end/numpy/single_line_docstring.txt +0 -0
  76. {format_docstring-0.1.8 → format_docstring-0.2.0}/tests/test_data/end_to_end/numpy/texts_are_rewrapped.txt +0 -0
  77. {format_docstring-0.1.8 → format_docstring-0.2.0}/tests/test_data/end_to_end/numpy/very_long_unbreakable_word.txt +0 -0
  78. {format_docstring-0.1.8 → format_docstring-0.2.0}/tests/test_data/integration_test/numpy/after.ipynb +0 -0
  79. {format_docstring-0.1.8 → format_docstring-0.2.0}/tests/test_data/integration_test/numpy/after.py +0 -0
  80. {format_docstring-0.1.8 → format_docstring-0.2.0}/tests/test_data/integration_test/numpy/after_50.ipynb +0 -0
  81. {format_docstring-0.1.8 → format_docstring-0.2.0}/tests/test_data/integration_test/numpy/after_50.py +0 -0
  82. {format_docstring-0.1.8 → format_docstring-0.2.0}/tests/test_data/integration_test/numpy/before.ipynb +0 -0
  83. {format_docstring-0.1.8 → format_docstring-0.2.0}/tests/test_data/integration_test/numpy/before.py +0 -0
  84. {format_docstring-0.1.8 → format_docstring-0.2.0}/tests/test_data/line_wrap/numpy/README.md +0 -0
  85. {format_docstring-0.1.8 → format_docstring-0.2.0}/tests/test_data/line_wrap/numpy/colon_spacing_fix.txt +0 -0
  86. {format_docstring-0.1.8 → format_docstring-0.2.0}/tests/test_data/line_wrap/numpy/contents_that_are_not_wrapped.txt +0 -0
  87. {format_docstring-0.1.8 → format_docstring-0.2.0}/tests/test_data/line_wrap/numpy/default_value_standardization.txt +0 -0
  88. {format_docstring-0.1.8 → format_docstring-0.2.0}/tests/test_data/line_wrap/numpy/empty_lines_are_respected.txt +0 -0
  89. {format_docstring-0.1.8 → format_docstring-0.2.0}/tests/test_data/line_wrap/numpy/examples_section.txt +0 -0
  90. {format_docstring-0.1.8 → format_docstring-0.2.0}/tests/test_data/line_wrap/numpy/existing_linebreaks_should_not_be_respected.txt +0 -0
  91. {format_docstring-0.1.8 → format_docstring-0.2.0}/tests/test_data/line_wrap/numpy/fix_rst_backticks.txt +0 -0
  92. {format_docstring-0.1.8 → format_docstring-0.2.0}/tests/test_data/line_wrap/numpy/indent_four_levels_16_spaces_width_10.txt +0 -0
  93. {format_docstring-0.1.8 → format_docstring-0.2.0}/tests/test_data/line_wrap/numpy/indent_two_levels_8_spaces.txt +0 -0
  94. {format_docstring-0.1.8 → format_docstring-0.2.0}/tests/test_data/line_wrap/numpy/line_length_2.txt +0 -0
  95. {format_docstring-0.1.8 → format_docstring-0.2.0}/tests/test_data/line_wrap/numpy/mismatched_underlines.txt +0 -0
  96. {format_docstring-0.1.8 → format_docstring-0.2.0}/tests/test_data/line_wrap/numpy/mismatched_underlines_one_dash.txt +0 -0
  97. {format_docstring-0.1.8 → format_docstring-0.2.0}/tests/test_data/line_wrap/numpy/mismatched_underlines_two_dashes.txt +0 -0
  98. {format_docstring-0.1.8 → format_docstring-0.2.0}/tests/test_data/line_wrap/numpy/module_level_docstring.txt +0 -0
  99. {format_docstring-0.1.8 → format_docstring-0.2.0}/tests/test_data/line_wrap/numpy/param_signature_without_type.txt +0 -0
  100. {format_docstring-0.1.8 → format_docstring-0.2.0}/tests/test_data/line_wrap/numpy/parameters_returns_raises_wrapping.txt +0 -0
  101. {format_docstring-0.1.8 → format_docstring-0.2.0}/tests/test_data/line_wrap/numpy/returns_signature_and_description.txt +0 -0
  102. {format_docstring-0.1.8 → format_docstring-0.2.0}/tests/test_data/line_wrap/numpy/section_title_fixed.txt +0 -0
  103. {format_docstring-0.1.8 → format_docstring-0.2.0}/tests/test_data/line_wrap/numpy/sections_notes_examples.txt +0 -0
  104. {format_docstring-0.1.8 → format_docstring-0.2.0}/tests/test_data/line_wrap/numpy/signature_line_is_not_wrapped.txt +0 -0
  105. {format_docstring-0.1.8 → format_docstring-0.2.0}/tests/test_data/line_wrap/numpy/texts_are_rewrapped.txt +0 -0
  106. {format_docstring-0.1.8 → format_docstring-0.2.0}/tests/test_data/line_wrap/numpy/very_long_unbreakable_word.txt +0 -0
  107. {format_docstring-0.1.8 → format_docstring-0.2.0}/tests/test_data/playground.py +0 -0
  108. {format_docstring-0.1.8 → format_docstring-0.2.0}/tests/test_line_wrap_google.py +0 -0
  109. {format_docstring-0.1.8 → format_docstring-0.2.0}/tests/test_line_wrap_utils.py +0 -0
  110. {format_docstring-0.1.8 → format_docstring-0.2.0}/tests/test_playground.py +0 -0
@@ -0,0 +1,83 @@
1
+ ---
2
+ repos:
3
+ - repo: https://github.com/pre-commit/pre-commit-hooks
4
+ rev: v6.0.0
5
+ hooks:
6
+ - id: trailing-whitespace
7
+ - id: end-of-file-fixer
8
+ exclude: \.json$|\.ipynb$
9
+ - id: debug-statements
10
+ - id: double-quote-string-fixer
11
+ - id: requirements-txt-fixer
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
21
+ - repo: https://github.com/asottile/pyupgrade
22
+ rev: v3.20.0
23
+ hooks:
24
+ - id: pyupgrade
25
+ args: [--py310-plus]
26
+ - repo: https://github.com/jsh9/muff-pre-commit
27
+ rev: 0.13.2
28
+ hooks:
29
+ - id: muff-format
30
+ args: [--config, muff.toml]
31
+ - repo: https://github.com/jsh9/blank-line-after-blocks
32
+ rev: 0.1.4
33
+ hooks:
34
+ - id: blank-line-after-blocks
35
+ - id: blank-line-after-blocks-jupyter
36
+ - repo: https://github.com/lyz-code/yamlfix
37
+ rev: 1.18.0
38
+ hooks:
39
+ - id: yamlfix
40
+ - repo: https://github.com/hukkin/mdformat
41
+ rev: 1.0.0
42
+ hooks:
43
+ - id: mdformat
44
+ args: [--wrap, '79', --number]
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
56
+ - repo: https://github.com/jsh9/markdown-toc-creator
57
+ rev: 0.0.11
58
+ hooks:
59
+ - id: markdown-toc-creator
60
+ - repo: local
61
+ hooks:
62
+ - id: format-docstring
63
+ name: Format self (python docstrings)
64
+ entry: python
65
+ args: [-m, format_docstring.main_py, --verbose, diff]
66
+ language: python
67
+ types: [python]
68
+ exclude: ^tests/test_data/
69
+ additional_dependencies:
70
+ - click>=8.0
71
+ - jupyter-notebook-parser>=0.1.4
72
+ - tomli>=1.1.0
73
+ - id: format-docstring-jupyter
74
+ name: Format self (docstrings in Jupyter notebooks)
75
+ entry: python
76
+ args: [-m, format_docstring.main_jupyter, --verbose, diff]
77
+ language: python
78
+ files: ^.*\.ipynb$
79
+ exclude: ^tests/test_data/
80
+ additional_dependencies:
81
+ - click>=8.0
82
+ - jupyter-notebook-parser>=0.1.4
83
+ - tomli>=1.1.0
@@ -0,0 +1,130 @@
1
+ # AGENTS.md
2
+
3
+ This guide briefs coding agents working on `format-docstring`. Use it to get
4
+ oriented before making changes.
5
+
6
+ ## Quick Snapshot
7
+
8
+ - Formats NumPy-style docstrings (with experimental Google support) in `.py`
9
+ files and Jupyter notebooks while preserving surrounding code.
10
+ - Distributed as a CLI (`format-docstring`, `format-docstring-jupyter`) with
11
+ minimum Python 3.10, packaged via `setuptools`.
12
+ - Core dependencies: `click`, `docstring_parser_fork`,
13
+ `jupyter-notebook-parser`, and `tomli/tomllib` for configuration loading.
14
+ - Version is sourced dynamically in `format_docstring/__init__.py`.
15
+
16
+ ## Repository Layout
17
+
18
+ - `format_docstring/main_py.py` – Click CLI for Python files; validates input
19
+ and delegates to `PythonFileFixer`.
20
+ - `format_docstring/main_jupyter.py` – CLI for `.ipynb` files built on
21
+ `JupyterNotebookParser`/`JupyterNotebookRewriter`.
22
+ - `format_docstring/base_fixer.py` – Shared directory traversal, exclusion
23
+ regex handling, and `fix_one_directory_or_one_file` orchestration.
24
+ - `format_docstring/docstring_rewriter.py` – AST-based docstring extraction and
25
+ replacement that leaves non-docstring text untouched.
26
+ - `format_docstring/line_wrap_numpy.py` / `line_wrap_google.py` –
27
+ Style-specific wrapping helpers; NumPy path is the production code path,
28
+ Google is partial.
29
+ - `format_docstring/line_wrap_utils.py` – Shared utilities for wrapping (indent
30
+ management, bullet handling, preserving literal blocks, etc.).
31
+ - `format_docstring/config.py` – `pyproject.toml` discovery, parsing, and Click
32
+ default injection.
33
+ - `tests/` – Pytest suite with fixture-driven cases in `tests/test_data/`; see
34
+ `tests/helpers.py` for fixture loading helpers.
35
+
36
+ ## Implementation Notes
37
+
38
+ - `docstring_rewriter.fix_src` parses with `ast.parse`, collects docstring
39
+ literals, and rewrites source slices using absolute offsets from
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.
47
+ - Wrapping honors NumPy section heuristics, rST constructs, code fences,
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.
52
+ - CLI exposes `--docstring-style`, but the Python entry-point currently raises
53
+ if a non-NumPy style is requested; Jupyter flow passes style through
54
+ unchanged.
55
+ - `BaseFixer` subclasses return `1` when any file changed so callers can
56
+ surface non-zero exit codes.
57
+ - Notebook fixer round-trips JSON via `json.dump(..., indent=1)` and rewrites
58
+ cells only when content changes, preserving magics with `reconstruct_source`.
59
+
60
+ ## Configuration
61
+
62
+ - User-facing configuration lives under `[tool.format_docstring]` inside
63
+ `pyproject.toml` and supports `line_length`, `docstring_style`, `exclude`,
64
+ `fix_rst_backticks`, and `verbose` (`default` or `diff` to print unified
65
+ diffs on rewrites).
66
+ - `config.inject_config_from_file` auto-discovers the nearest `pyproject.toml`
67
+ (walking up from targets) and merges values into Click’s `default_map`.
68
+ - Default exclude pattern is `\.git|\.tox|\.pytest_cache`; tests tweak it as
69
+ needed.
70
+
71
+ ## Development Workflow
72
+
73
+ - Install: `pip install -e .` for the project,
74
+ `pip install -r requirements.dev` for tooling.
75
+ - Tests: `pytest --tb=long`, or target modules such as
76
+ `pytest tests/test_docstring_rewriter.py`.
77
+ - Lint/format: `muff check --fix --config=muff.toml format_docstring tests`,
78
+ `muff format --diff --config=muff.toml format_docstring tests`.
79
+ - Type checking: `mypy format_docstring/`.
80
+ - Tox: `tox` for the full matrix (py310–py313, mypy, lint), or focused runs
81
+ like `tox -e py311`, `tox -e mypy`, `tox -e muff-format`.
82
+ - CLI smoke tests: `format-docstring --help`,
83
+ `format-docstring-jupyter --help`.
84
+ - Pre-commit: `pre-commit run -a`.
85
+
86
+ ## Testing Notes
87
+
88
+ - Fixture files under `tests/test_data/line_wrap` and
89
+ `tests/test_data/end_to_end` use `LINE_LENGTH: <int>` headers followed by
90
+ `BEFORE`/`AFTER` sections split by `**********`.
91
+ - `tests/test_playground.py` focuses on regression snippets;
92
+ `tests/test_config.py` exercises config discovery and CLI overrides.
93
+ - When modifying wrapping rules, update both the helper (`line_wrap_utils.py`)
94
+ and the corresponding expectation files in `tests/test_data/`.
95
+
96
+ ## Style Guidance
97
+
98
+ - Formatting rules mirror `muff.toml` (line length 79, single quotes, NumPy
99
+ docstring convention). Respect these when adding code.
100
+ - Keep docstring style tests conservative: avoid mutating non-docstring
101
+ content, and add regression cases whenever handling around literal sections
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,29 @@ 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
+
18
+ ## [0.1.9] - 2025-10-16
19
+
20
+ - Added
21
+ - A "`# no-format-docstring`" directive to ignore certain docstring
22
+ - Verbose diff output via `--verbose diff` and
23
+ `[tool.format_docstring] verbose`
24
+ - Normalize NumPy section headings that include trailing colons (e.g.,
25
+ `Parameters:`); also, fix Google-style "Arg" header into "Parameters"
26
+ - Changed
27
+ - Added "self format" pre-commit hook to format docstrings within this repo
28
+ with its own formatting logic
29
+ - Full diff
30
+ - https://github.com/jsh9/format-docstring/compare/0.1.8...0.1.9
31
+
9
32
  ## [0.1.8] - 2025-10-14
10
33
 
11
34
  - Fixed
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: format-docstring
3
- Version: 0.1.8
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>
@@ -27,7 +27,6 @@ Description-Content-Type: text/markdown
27
27
  License-File: LICENSE
28
28
  Requires-Dist: jupyter-notebook-parser>=0.1.4
29
29
  Requires-Dist: click>=8.0
30
- Requires-Dist: docstring_parser_fork>=0.0.14
31
30
  Requires-Dist: tomli>=1.1.0; python_version < "3.11"
32
31
  Dynamic: license-file
33
32
 
@@ -35,6 +34,8 @@ Dynamic: license-file
35
34
 
36
35
  A Python formatter to automatically format numpy-style docstrings.
37
36
 
37
+ ______________________________________________________________________
38
+
38
39
  **Table of Contents:**
39
40
 
40
41
  <!--TOC-->
@@ -46,32 +47,38 @@ A Python formatter to automatically format numpy-style docstrings.
46
47
  - [2.3. Minor typos can be automatically fixed](#23-minor-typos-can-be-automatically-fixed)
47
48
  - [2.4. Default value declarations are standardized](#24-default-value-declarations-are-standardized)
48
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)
49
51
  - [3. Installation](#3-installation)
50
52
  - [4. Usage](#4-usage)
51
53
  - [4.1. Command Line Interface](#41-command-line-interface)
52
54
  - [4.2. Pre-commit Hook](#42-pre-commit-hook)
55
+ - [4.3. Opting Out of Formatting](#43-opting-out-of-formatting)
53
56
  - [5. Configuration](#5-configuration)
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
@@ -281,6 +392,19 @@ Then install the pre-commit hook:
281
392
  pre-commit install
282
393
  ```
283
394
 
395
+ ### 4.3. Opting Out of Formatting
396
+
397
+ Add a comment containing `no-format-docstring` on the same line as the closing
398
+ triple quotes to prevent the formatter from touching that docstring:
399
+ `""" ... """ # no-format-docstring`.
400
+
401
+ You can combine this "no-format-docstring" with other directives like "noqa".
402
+
403
+ Tip: If you only want to keep specific formatter changes inside a docstring,
404
+ first run `format-docstring`, accept the parts you like, revert the edits you
405
+ dislike, and then add an inline `# no-format-docstring` comment so future runs
406
+ leave that docstring untouched.
407
+
284
408
  ## 5. Configuration
285
409
 
286
410
  ### 5.1. Command-Line Options
@@ -291,6 +415,8 @@ pre-commit install
291
415
  default: `numpy`). Note: Currently only `numpy` style is fully supported.
292
416
  - `--fix-rst-backticks BOOL`: Automatically fix single backticks to double
293
417
  backticks per rST syntax (default: True)
418
+ - `--verbose CHOICE`: Logging detail level (`default` keeps the existing
419
+ behaviour, `diff` prints unified diffs when rewrites happen)
294
420
  - `--exclude TEXT`: Regex pattern to exclude files/directories (default:
295
421
  `\.git|\.tox|\.pytest_cache`)
296
422
  - `--config PATH`: Path to a `pyproject.toml` config file. If not specified,
@@ -311,6 +437,9 @@ format-docstring --line-length 72 src/
311
437
  # Format Jupyter notebooks excluding certain directories
312
438
  format-docstring-jupyter --exclude "\.git|\.venv|__pycache__" notebooks/
313
439
 
440
+ # Preview changes with unified diffs
441
+ format-docstring --verbose diff src/
442
+
314
443
  # Use a specific config file
315
444
  format-docstring --config path/to/pyproject.toml src/
316
445
 
@@ -332,6 +461,7 @@ line_length = 79
332
461
  docstring_style = "numpy"
333
462
  fix_rst_backticks = true
334
463
  exclude = "\\.git|\\.venv|__pycache__"
464
+ verbose = "default" # or "diff" to print unified diffs
335
465
  ```
336
466
 
337
467
  **Available options:**
@@ -344,6 +474,21 @@ exclude = "\\.git|\\.venv|__pycache__"
344
474
  backticks per rST syntax (default: `true`)
345
475
  - `exclude` (str): Regex pattern to exclude files/directories (default:
346
476
  `"\\.git|\\.tox|\\.pytest_cache"`)
477
+ - `verbose` (str): Logging detail level (`"default"` or `"diff"`)
347
478
 
348
479
  The tool searches for `pyproject.toml` starting from the target file/directory
349
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