docstringify 0.6.0__tar.gz → 1.0.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.
- {docstringify-0.6.0 → docstringify-1.0.0}/.pre-commit-config.yaml +4 -4
- {docstringify-0.6.0 → docstringify-1.0.0}/PKG-INFO +30 -10
- {docstringify-0.6.0 → docstringify-1.0.0}/README.md +28 -8
- {docstringify-0.6.0 → docstringify-1.0.0}/pyproject.toml +1 -1
- {docstringify-0.6.0 → docstringify-1.0.0}/src/docstringify/__init__.py +1 -1
- {docstringify-0.6.0 → docstringify-1.0.0}/src/docstringify/cli.py +23 -12
- {docstringify-0.6.0 → docstringify-1.0.0}/src/docstringify/converters/__init__.py +2 -0
- {docstringify-0.6.0 → docstringify-1.0.0}/src/docstringify/converters/base.py +15 -8
- {docstringify-0.6.0 → docstringify-1.0.0}/src/docstringify/converters/google.py +1 -1
- {docstringify-0.6.0 → docstringify-1.0.0}/src/docstringify/converters/numpydoc.py +1 -1
- docstringify-1.0.0/src/docstringify/converters/stub.py +121 -0
- docstringify-1.0.0/src/docstringify/exceptions.py +25 -0
- {docstringify-0.6.0 → docstringify-1.0.0}/src/docstringify/nodes/base.py +6 -4
- {docstringify-0.6.0 → docstringify-1.0.0}/src/docstringify/nodes/function.py +54 -20
- {docstringify-0.6.0 → docstringify-1.0.0}/src/docstringify/traversal/transformer.py +81 -14
- {docstringify-0.6.0 → docstringify-1.0.0}/src/docstringify/traversal/visitor.py +37 -9
- {docstringify-0.6.0 → docstringify-1.0.0}/src/docstringify.egg-info/PKG-INFO +30 -10
- {docstringify-0.6.0 → docstringify-1.0.0}/src/docstringify.egg-info/SOURCES.txt +1 -0
- docstringify-0.6.0/src/docstringify/exceptions.py +0 -6
- {docstringify-0.6.0 → docstringify-1.0.0}/.github/ISSUE_TEMPLATE/bug_report.md +0 -0
- {docstringify-0.6.0 → docstringify-1.0.0}/.github/ISSUE_TEMPLATE/feature_request.md +0 -0
- {docstringify-0.6.0 → docstringify-1.0.0}/.github/dependabot.yml +0 -0
- {docstringify-0.6.0 → docstringify-1.0.0}/.github/pull_request_template.md +0 -0
- {docstringify-0.6.0 → docstringify-1.0.0}/.github/release.yml +0 -0
- {docstringify-0.6.0 → docstringify-1.0.0}/.github/workflows/ci.yml +0 -0
- {docstringify-0.6.0 → docstringify-1.0.0}/.github/workflows/greetings.yml +0 -0
- {docstringify-0.6.0 → docstringify-1.0.0}/.github/workflows/pypi-publish.yml +0 -0
- {docstringify-0.6.0 → docstringify-1.0.0}/.gitignore +0 -0
- {docstringify-0.6.0 → docstringify-1.0.0}/.pre-commit-hooks.yaml +0 -0
- {docstringify-0.6.0 → docstringify-1.0.0}/CODE_OF_CONDUCT.md +0 -0
- {docstringify-0.6.0 → docstringify-1.0.0}/CONTRIBUTING.md +0 -0
- {docstringify-0.6.0 → docstringify-1.0.0}/LICENSE +0 -0
- {docstringify-0.6.0 → docstringify-1.0.0}/setup.cfg +0 -0
- {docstringify-0.6.0 → docstringify-1.0.0}/src/docstringify/__main__.py +0 -0
- {docstringify-0.6.0 → docstringify-1.0.0}/src/docstringify/components.py +0 -0
- {docstringify-0.6.0 → docstringify-1.0.0}/src/docstringify/nodes/__init__.py +0 -0
- {docstringify-0.6.0 → docstringify-1.0.0}/src/docstringify/traversal/__init__.py +0 -0
- {docstringify-0.6.0 → docstringify-1.0.0}/src/docstringify.egg-info/dependency_links.txt +0 -0
- {docstringify-0.6.0 → docstringify-1.0.0}/src/docstringify.egg-info/entry_points.txt +0 -0
- {docstringify-0.6.0 → docstringify-1.0.0}/src/docstringify.egg-info/requires.txt +0 -0
- {docstringify-0.6.0 → docstringify-1.0.0}/src/docstringify.egg-info/top_level.txt +0 -0
|
@@ -12,20 +12,20 @@ repos:
|
|
|
12
12
|
- id: trailing-whitespace
|
|
13
13
|
|
|
14
14
|
- repo: https://github.com/stefmolin/docstringify
|
|
15
|
-
rev: 0.
|
|
15
|
+
rev: 0.7.0
|
|
16
16
|
hooks:
|
|
17
17
|
- id: docstringify
|
|
18
18
|
args: [--make-changes-inplace=numpydoc]
|
|
19
19
|
|
|
20
20
|
- repo: https://github.com/astral-sh/ruff-pre-commit
|
|
21
|
-
rev: v0.11.
|
|
21
|
+
rev: v0.11.10
|
|
22
22
|
hooks:
|
|
23
|
-
- id: ruff
|
|
23
|
+
- id: ruff-check
|
|
24
24
|
args: [--fix, --exit-non-zero-on-fix, --show-fixes]
|
|
25
25
|
- id: ruff-format
|
|
26
26
|
|
|
27
27
|
- repo: https://github.com/tox-dev/pyproject-fmt
|
|
28
|
-
rev: v2.
|
|
28
|
+
rev: v2.6.0
|
|
29
29
|
hooks:
|
|
30
30
|
- id: pyproject-fmt
|
|
31
31
|
args: [--keep-full-version, --no-print-diff]
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: docstringify
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 1.0.0
|
|
4
4
|
Summary: Flag missing docstrings and, optionally, generate them from signatures and type annotations.
|
|
5
5
|
Author-email: Stefanie Molin <docstringify@stefaniemolin.com>
|
|
6
6
|
License: MIT License
|
|
@@ -29,7 +29,7 @@ Project-URL: Documentation, https://github.com/stefmolin/docstringify
|
|
|
29
29
|
Project-URL: Homepage, https://github.com/stefmolin/docstringify
|
|
30
30
|
Project-URL: Source, https://github.com/stefmolin/docstringify
|
|
31
31
|
Keywords: ast,docstring generation,google-style docstring,numpydoc-style docstring,pre-commit
|
|
32
|
-
Classifier: Development Status ::
|
|
32
|
+
Classifier: Development Status :: 4 - Beta
|
|
33
33
|
Classifier: Programming Language :: Python
|
|
34
34
|
Classifier: Programming Language :: Python :: 3 :: Only
|
|
35
35
|
Classifier: Programming Language :: Python :: 3.9
|
|
@@ -103,11 +103,11 @@ You can use Docstringify in three modes:
|
|
|
103
103
|
|
|
104
104
|
### Pre-commit hook
|
|
105
105
|
|
|
106
|
-
Add the following to your `.pre-commit-config.yaml` file to block commits with missing docstrings
|
|
106
|
+
Add the following to your `.pre-commit-config.yaml` file to block commits with missing docstrings before any formatters like `ruff`:
|
|
107
107
|
|
|
108
108
|
```yaml
|
|
109
109
|
- repo: https://github.com/stefmolin/docstringify
|
|
110
|
-
rev: 0.
|
|
110
|
+
rev: 1.0.0
|
|
111
111
|
hooks:
|
|
112
112
|
- id: docstringify
|
|
113
113
|
```
|
|
@@ -116,17 +116,17 @@ By default, all docstrings are required. If you want to be more lenient, you can
|
|
|
116
116
|
|
|
117
117
|
```yaml
|
|
118
118
|
- repo: https://github.com/stefmolin/docstringify
|
|
119
|
-
rev: 0.
|
|
119
|
+
rev: 1.0.0
|
|
120
120
|
hooks:
|
|
121
121
|
- id: docstringify
|
|
122
122
|
args: [--threshold=0.75]
|
|
123
123
|
```
|
|
124
124
|
|
|
125
|
-
If you would like to see suggested docstring templates (inferred from type annotations for functions and methods), provide the `--suggest-changes` argument, along with the docstring style you want to use (options are `google` and `
|
|
125
|
+
If you would like to see suggested docstring templates (inferred from type annotations for functions and methods), provide the `--suggest-changes` argument, along with the docstring style you want to use (options are `google`, `numpydoc`, and `stub`). Here, we ask for stub suggestions (just single lines of `"""__description__"""`):
|
|
126
126
|
|
|
127
127
|
```yaml
|
|
128
128
|
- repo: https://github.com/stefmolin/docstringify
|
|
129
|
-
rev: 0.
|
|
129
|
+
rev: 1.0.0
|
|
130
130
|
hooks:
|
|
131
131
|
- id: docstringify
|
|
132
132
|
args: [--suggest-changes=numpydoc]
|
|
@@ -136,13 +136,21 @@ Use `--make-changes` to create a copy of each file with docstring templates. Her
|
|
|
136
136
|
|
|
137
137
|
```yaml
|
|
138
138
|
- repo: https://github.com/stefmolin/docstringify
|
|
139
|
-
rev: 0.
|
|
139
|
+
rev: 1.0.0
|
|
140
140
|
hooks:
|
|
141
141
|
- id: docstringify
|
|
142
142
|
args: [--make-changes=google]
|
|
143
143
|
```
|
|
144
144
|
|
|
145
|
-
If you want the changes to be made in place, change `--make-changes` to `--make-changes-inplace` – make sure you only operate on files that are in version control with this setting.
|
|
145
|
+
If you want the changes to be made in place, change `--make-changes` to `--make-changes-inplace` – make sure you only operate on files that are in version control with this setting. Here, we ask for [numpydoc-style docstring](https://numpydoc.readthedocs.io/en/latest/format.html#) suggestions:
|
|
146
|
+
|
|
147
|
+
```yaml
|
|
148
|
+
- repo: https://github.com/stefmolin/docstringify
|
|
149
|
+
rev: 1.0.0
|
|
150
|
+
hooks:
|
|
151
|
+
- id: docstringify
|
|
152
|
+
args: [--make-changes-inplace=numpydoc]
|
|
153
|
+
```
|
|
146
154
|
|
|
147
155
|
Be sure to check out the [pre-commit documentation](https://pre-commit.com/#pre-commit-configyaml---hooks) for additional configuration options.
|
|
148
156
|
|
|
@@ -216,7 +224,19 @@ test.say_hello is missing a docstring
|
|
|
216
224
|
Docstring templates written to /.../test_docstringify.py
|
|
217
225
|
```
|
|
218
226
|
|
|
219
|
-
If you want to overwrite the file with the edits, pass `overwrite=True` to `DocstringTransformer()
|
|
227
|
+
If you want to overwrite the file with the edits, pass `overwrite=True` to `DocstringTransformer()`:
|
|
228
|
+
|
|
229
|
+
```pycon
|
|
230
|
+
>>> from docstringify.converters import GoogleDocstringConverter
|
|
231
|
+
>>> from docstringify.traversal import DocstringTransformer
|
|
232
|
+
>>> transformer = DocstringTransformer(
|
|
233
|
+
... 'test.py', converter=GoogleDocstringConverter, overwrite=True
|
|
234
|
+
... )
|
|
235
|
+
>>> transformer.process_file()
|
|
236
|
+
test is missing a docstring
|
|
237
|
+
test.say_hello is missing a docstring
|
|
238
|
+
Docstring templates written to /.../test.py
|
|
239
|
+
```
|
|
220
240
|
|
|
221
241
|
## Contributing
|
|
222
242
|
|
|
@@ -54,11 +54,11 @@ You can use Docstringify in three modes:
|
|
|
54
54
|
|
|
55
55
|
### Pre-commit hook
|
|
56
56
|
|
|
57
|
-
Add the following to your `.pre-commit-config.yaml` file to block commits with missing docstrings
|
|
57
|
+
Add the following to your `.pre-commit-config.yaml` file to block commits with missing docstrings before any formatters like `ruff`:
|
|
58
58
|
|
|
59
59
|
```yaml
|
|
60
60
|
- repo: https://github.com/stefmolin/docstringify
|
|
61
|
-
rev: 0.
|
|
61
|
+
rev: 1.0.0
|
|
62
62
|
hooks:
|
|
63
63
|
- id: docstringify
|
|
64
64
|
```
|
|
@@ -67,17 +67,17 @@ By default, all docstrings are required. If you want to be more lenient, you can
|
|
|
67
67
|
|
|
68
68
|
```yaml
|
|
69
69
|
- repo: https://github.com/stefmolin/docstringify
|
|
70
|
-
rev: 0.
|
|
70
|
+
rev: 1.0.0
|
|
71
71
|
hooks:
|
|
72
72
|
- id: docstringify
|
|
73
73
|
args: [--threshold=0.75]
|
|
74
74
|
```
|
|
75
75
|
|
|
76
|
-
If you would like to see suggested docstring templates (inferred from type annotations for functions and methods), provide the `--suggest-changes` argument, along with the docstring style you want to use (options are `google` and `
|
|
76
|
+
If you would like to see suggested docstring templates (inferred from type annotations for functions and methods), provide the `--suggest-changes` argument, along with the docstring style you want to use (options are `google`, `numpydoc`, and `stub`). Here, we ask for stub suggestions (just single lines of `"""__description__"""`):
|
|
77
77
|
|
|
78
78
|
```yaml
|
|
79
79
|
- repo: https://github.com/stefmolin/docstringify
|
|
80
|
-
rev: 0.
|
|
80
|
+
rev: 1.0.0
|
|
81
81
|
hooks:
|
|
82
82
|
- id: docstringify
|
|
83
83
|
args: [--suggest-changes=numpydoc]
|
|
@@ -87,13 +87,21 @@ Use `--make-changes` to create a copy of each file with docstring templates. Her
|
|
|
87
87
|
|
|
88
88
|
```yaml
|
|
89
89
|
- repo: https://github.com/stefmolin/docstringify
|
|
90
|
-
rev: 0.
|
|
90
|
+
rev: 1.0.0
|
|
91
91
|
hooks:
|
|
92
92
|
- id: docstringify
|
|
93
93
|
args: [--make-changes=google]
|
|
94
94
|
```
|
|
95
95
|
|
|
96
|
-
If you want the changes to be made in place, change `--make-changes` to `--make-changes-inplace` – make sure you only operate on files that are in version control with this setting.
|
|
96
|
+
If you want the changes to be made in place, change `--make-changes` to `--make-changes-inplace` – make sure you only operate on files that are in version control with this setting. Here, we ask for [numpydoc-style docstring](https://numpydoc.readthedocs.io/en/latest/format.html#) suggestions:
|
|
97
|
+
|
|
98
|
+
```yaml
|
|
99
|
+
- repo: https://github.com/stefmolin/docstringify
|
|
100
|
+
rev: 1.0.0
|
|
101
|
+
hooks:
|
|
102
|
+
- id: docstringify
|
|
103
|
+
args: [--make-changes-inplace=numpydoc]
|
|
104
|
+
```
|
|
97
105
|
|
|
98
106
|
Be sure to check out the [pre-commit documentation](https://pre-commit.com/#pre-commit-configyaml---hooks) for additional configuration options.
|
|
99
107
|
|
|
@@ -167,7 +175,19 @@ test.say_hello is missing a docstring
|
|
|
167
175
|
Docstring templates written to /.../test_docstringify.py
|
|
168
176
|
```
|
|
169
177
|
|
|
170
|
-
If you want to overwrite the file with the edits, pass `overwrite=True` to `DocstringTransformer()
|
|
178
|
+
If you want to overwrite the file with the edits, pass `overwrite=True` to `DocstringTransformer()`:
|
|
179
|
+
|
|
180
|
+
```pycon
|
|
181
|
+
>>> from docstringify.converters import GoogleDocstringConverter
|
|
182
|
+
>>> from docstringify.traversal import DocstringTransformer
|
|
183
|
+
>>> transformer = DocstringTransformer(
|
|
184
|
+
... 'test.py', converter=GoogleDocstringConverter, overwrite=True
|
|
185
|
+
... )
|
|
186
|
+
>>> transformer.process_file()
|
|
187
|
+
test is missing a docstring
|
|
188
|
+
test.say_hello is missing a docstring
|
|
189
|
+
Docstring templates written to /.../test.py
|
|
190
|
+
```
|
|
171
191
|
|
|
172
192
|
## Contributing
|
|
173
193
|
|
|
@@ -23,7 +23,7 @@ authors = [
|
|
|
23
23
|
]
|
|
24
24
|
requires-python = ">=3.9"
|
|
25
25
|
classifiers = [
|
|
26
|
-
"Development Status ::
|
|
26
|
+
"Development Status :: 4 - Beta",
|
|
27
27
|
"Programming Language :: Python",
|
|
28
28
|
"Programming Language :: Python :: 3 :: Only",
|
|
29
29
|
"Programming Language :: Python :: 3.9",
|
|
@@ -9,14 +9,28 @@ from typing import TYPE_CHECKING
|
|
|
9
9
|
|
|
10
10
|
from . import __doc__ as pkg_description
|
|
11
11
|
from . import __version__
|
|
12
|
-
from .converters import
|
|
12
|
+
from .converters import (
|
|
13
|
+
GoogleDocstringConverter,
|
|
14
|
+
NumpydocDocstringConverter,
|
|
15
|
+
StubDocstringConverter,
|
|
16
|
+
)
|
|
13
17
|
from .traversal import DocstringTransformer, DocstringVisitor
|
|
14
18
|
|
|
15
19
|
if TYPE_CHECKING:
|
|
16
20
|
from collections.abc import Sequence
|
|
17
21
|
|
|
22
|
+
|
|
18
23
|
PROG = __package__
|
|
19
|
-
STYLES
|
|
24
|
+
STYLES: dict[
|
|
25
|
+
str,
|
|
26
|
+
type[GoogleDocstringConverter]
|
|
27
|
+
| type[NumpydocDocstringConverter]
|
|
28
|
+
| type[StubDocstringConverter],
|
|
29
|
+
] = {
|
|
30
|
+
'google': GoogleDocstringConverter,
|
|
31
|
+
'numpydoc': NumpydocDocstringConverter,
|
|
32
|
+
'stub': StubDocstringConverter,
|
|
33
|
+
}
|
|
20
34
|
CLI_DEFAULTS = {'threshold': 1.0}
|
|
21
35
|
|
|
22
36
|
|
|
@@ -74,22 +88,19 @@ def main(argv: Sequence[str] | None = None) -> int:
|
|
|
74
88
|
)
|
|
75
89
|
args = parser.parse_args(argv)
|
|
76
90
|
|
|
77
|
-
if style := (
|
|
78
|
-
args.make_changes or args.make_changes_inplace or args.suggest_changes
|
|
79
|
-
):
|
|
80
|
-
converter = STYLES[style]
|
|
81
|
-
else:
|
|
82
|
-
converter = None
|
|
83
|
-
|
|
84
91
|
get_docstring_processor = (
|
|
85
92
|
partial(
|
|
86
93
|
DocstringTransformer,
|
|
87
|
-
converter=
|
|
94
|
+
converter=STYLES[style],
|
|
88
95
|
overwrite=bool(args.make_changes_inplace),
|
|
89
96
|
verbose=args.verbose,
|
|
90
97
|
)
|
|
91
|
-
if args.make_changes or args.make_changes_inplace
|
|
92
|
-
else partial(
|
|
98
|
+
if (style := args.make_changes or args.make_changes_inplace)
|
|
99
|
+
else partial(
|
|
100
|
+
DocstringVisitor,
|
|
101
|
+
converter=STYLES.get(args.suggest_changes),
|
|
102
|
+
verbose=args.verbose,
|
|
103
|
+
)
|
|
93
104
|
)
|
|
94
105
|
|
|
95
106
|
docstrings_processed = missing_docstrings = 0
|
|
@@ -3,9 +3,11 @@
|
|
|
3
3
|
from .base import DocstringConverter
|
|
4
4
|
from .google import GoogleDocstringConverter
|
|
5
5
|
from .numpydoc import NumpydocDocstringConverter
|
|
6
|
+
from .stub import StubDocstringConverter
|
|
6
7
|
|
|
7
8
|
__all__ = [
|
|
8
9
|
'DocstringConverter',
|
|
9
10
|
'GoogleDocstringConverter',
|
|
10
11
|
'NumpydocDocstringConverter',
|
|
12
|
+
'StubDocstringConverter',
|
|
11
13
|
]
|
|
@@ -8,11 +8,11 @@ from abc import ABC, abstractmethod
|
|
|
8
8
|
from typing import TYPE_CHECKING
|
|
9
9
|
|
|
10
10
|
from ..exceptions import InvalidDocstringError
|
|
11
|
+
from ..nodes.function import FunctionDocstringNode
|
|
11
12
|
|
|
12
13
|
if TYPE_CHECKING:
|
|
13
14
|
from ..components import Parameter
|
|
14
15
|
from ..nodes.base import DocstringNode
|
|
15
|
-
from ..nodes.function import FunctionDocstringNode
|
|
16
16
|
|
|
17
17
|
|
|
18
18
|
class DocstringConverter(ABC):
|
|
@@ -184,7 +184,9 @@ class DocstringConverter(ABC):
|
|
|
184
184
|
return self._returns_section_template.format(returns=return_text)
|
|
185
185
|
return ''
|
|
186
186
|
|
|
187
|
-
def format_docstring(
|
|
187
|
+
def format_docstring(
|
|
188
|
+
self, docstring: str | list[str], indent: int, quote: bool | None = None
|
|
189
|
+
) -> str:
|
|
188
190
|
"""
|
|
189
191
|
Format the docstring with the requested level of indentation and surrounding
|
|
190
192
|
triple quotes, if requested.
|
|
@@ -195,23 +197,28 @@ class DocstringConverter(ABC):
|
|
|
195
197
|
The docstring as a string or list of strings that form lines in the docstring.
|
|
196
198
|
indent : int
|
|
197
199
|
The number of spaces by which to indent the docstring.
|
|
200
|
+
quote : bool | None, default=None
|
|
201
|
+
Whether to surround the docstring in triple quotes, passing this overrides
|
|
202
|
+
the ``quote`` setting specified upon initialization.
|
|
198
203
|
|
|
199
204
|
Returns
|
|
200
205
|
-------
|
|
201
206
|
str
|
|
202
207
|
The docstring indented to ``indent`` spaces will be returned either as a
|
|
203
|
-
quoted docstring if the converter was initialized with ``quote=True
|
|
204
|
-
|
|
208
|
+
quoted docstring if the converter was initialized with ``quote=True`` or
|
|
209
|
+
``quote=True`` was passed when calling this method, or an unquoted
|
|
210
|
+
docstring otherwise.
|
|
205
211
|
"""
|
|
206
|
-
|
|
212
|
+
quote_char = '"""' if quote or self._quote else ''
|
|
207
213
|
prefix = sep = ''
|
|
214
|
+
|
|
208
215
|
if isinstance(docstring, str):
|
|
209
|
-
docstring = [
|
|
216
|
+
docstring = [quote_char, docstring, quote_char]
|
|
210
217
|
elif isinstance(docstring, list):
|
|
211
218
|
if len(docstring) > 1:
|
|
212
219
|
prefix = ' ' * indent if indent else ''
|
|
213
220
|
sep = '\n'
|
|
214
|
-
docstring = [
|
|
221
|
+
docstring = [quote_char, *docstring, quote_char or f'{prefix}']
|
|
215
222
|
else:
|
|
216
223
|
raise InvalidDocstringError(type(docstring).__name__)
|
|
217
224
|
|
|
@@ -238,7 +245,7 @@ class DocstringConverter(ABC):
|
|
|
238
245
|
str | None
|
|
239
246
|
The suggested docstring.
|
|
240
247
|
"""
|
|
241
|
-
if isinstance(docstring_node
|
|
248
|
+
if isinstance(docstring_node, FunctionDocstringNode):
|
|
242
249
|
return (
|
|
243
250
|
self.to_function_docstring(docstring_node, indent=indent)
|
|
244
251
|
if docstring_node.docstring_required
|
|
@@ -81,7 +81,7 @@ class GoogleDocstringConverter(DocstringConverter):
|
|
|
81
81
|
category = f'{f", {parameter.category}" if parameter.category else ""}'
|
|
82
82
|
return (
|
|
83
83
|
f' {parameter.name} ({parameter.type_}{category}): {DESCRIPTION_PLACEHOLDER}'
|
|
84
|
-
f'{f" Defaults to {parameter.default}." if parameter.default
|
|
84
|
+
f'{f" Defaults to {parameter.default}." if parameter.default is not NO_DEFAULT else ""}'
|
|
85
85
|
)
|
|
86
86
|
|
|
87
87
|
def format_return(self, return_type: str | None) -> str:
|
|
@@ -81,7 +81,7 @@ class NumpydocDocstringConverter(DocstringConverter):
|
|
|
81
81
|
return (
|
|
82
82
|
f'{parameter.name} : {parameter.type_}'
|
|
83
83
|
f'{f", {parameter.category}" if parameter.category else ""}'
|
|
84
|
-
f'{f", default={parameter.default}" if parameter.default
|
|
84
|
+
f'{f", default={parameter.default}" if parameter.default is not NO_DEFAULT else ""}'
|
|
85
85
|
f'\n {DESCRIPTION_PLACEHOLDER}'
|
|
86
86
|
)
|
|
87
87
|
|
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
"""Stub docstring converter."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
from typing import TYPE_CHECKING
|
|
6
|
+
|
|
7
|
+
from ..components import DESCRIPTION_PLACEHOLDER, Parameter
|
|
8
|
+
from .base import DocstringConverter
|
|
9
|
+
|
|
10
|
+
if TYPE_CHECKING:
|
|
11
|
+
from ..nodes.base import DocstringNode
|
|
12
|
+
from ..nodes.function import FunctionDocstringNode
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
class StubDocstringConverter(DocstringConverter):
|
|
16
|
+
"""
|
|
17
|
+
Class defining the DocstringConverter API for injecting ``__description__`` stubs only.
|
|
18
|
+
|
|
19
|
+
Parameters
|
|
20
|
+
----------
|
|
21
|
+
quote : bool
|
|
22
|
+
Whether to surround the generated docstrings in triple quotes.
|
|
23
|
+
"""
|
|
24
|
+
|
|
25
|
+
def __init__(self, quote: bool) -> None:
|
|
26
|
+
super().__init__(
|
|
27
|
+
parameters_section_template='', returns_section_template='', quote=quote
|
|
28
|
+
)
|
|
29
|
+
|
|
30
|
+
def to_function_docstring(
|
|
31
|
+
self, docstring_node: FunctionDocstringNode, indent: int
|
|
32
|
+
) -> str:
|
|
33
|
+
"""
|
|
34
|
+
Convert an AST node into a function docstring.
|
|
35
|
+
|
|
36
|
+
Parameters
|
|
37
|
+
----------
|
|
38
|
+
docstring_node : FunctionDocstringNode
|
|
39
|
+
An instance of :class:`.FunctionDocstringNode`, which wraps an instance of
|
|
40
|
+
:class:`ast.FunctionDef` or :class:`ast.AsyncFunctionDef`, adding additional
|
|
41
|
+
context relevant for Docstringify.
|
|
42
|
+
indent : int
|
|
43
|
+
The number of spaces by which to indent the docstring.
|
|
44
|
+
|
|
45
|
+
Returns
|
|
46
|
+
-------
|
|
47
|
+
str
|
|
48
|
+
The function docstring.
|
|
49
|
+
"""
|
|
50
|
+
return self.format_docstring(DESCRIPTION_PLACEHOLDER, indent=indent)
|
|
51
|
+
|
|
52
|
+
def format_parameter(self, parameter: Parameter) -> str:
|
|
53
|
+
"""
|
|
54
|
+
Convert a :class:`.Parameter` instance into an entry in the parameters section
|
|
55
|
+
of the docstring.
|
|
56
|
+
|
|
57
|
+
Parameters
|
|
58
|
+
----------
|
|
59
|
+
parameter : Parameter
|
|
60
|
+
Information on the function parameter, including its name, type, and default
|
|
61
|
+
value (if it has one).
|
|
62
|
+
|
|
63
|
+
Returns
|
|
64
|
+
-------
|
|
65
|
+
str
|
|
66
|
+
An empty string.
|
|
67
|
+
"""
|
|
68
|
+
return ''
|
|
69
|
+
|
|
70
|
+
def format_return(self, return_type: str | None) -> str:
|
|
71
|
+
"""
|
|
72
|
+
Convert a return type into an entry in the returns section of the docstring.
|
|
73
|
+
|
|
74
|
+
Parameters
|
|
75
|
+
----------
|
|
76
|
+
return_type : str | None
|
|
77
|
+
The return type name for the function. This will be either a string for the
|
|
78
|
+
name (e.g., ``list[str]``) or ``None``, if ``None`` is returned.
|
|
79
|
+
|
|
80
|
+
Returns
|
|
81
|
+
-------
|
|
82
|
+
str
|
|
83
|
+
An empty string.
|
|
84
|
+
"""
|
|
85
|
+
return ''
|
|
86
|
+
|
|
87
|
+
def to_module_docstring(self, docstring_node: DocstringNode) -> str:
|
|
88
|
+
"""
|
|
89
|
+
Convert an AST node into a module docstring.
|
|
90
|
+
|
|
91
|
+
Parameters
|
|
92
|
+
----------
|
|
93
|
+
docstring_node : DocstringNode
|
|
94
|
+
An instance of :class:`.DocstringNode`, which wraps an instance of
|
|
95
|
+
:class:`ast.Module`, adding additional context relevant for Docstringify.
|
|
96
|
+
|
|
97
|
+
Returns
|
|
98
|
+
-------
|
|
99
|
+
str
|
|
100
|
+
The module docstring.
|
|
101
|
+
"""
|
|
102
|
+
return self.format_docstring(DESCRIPTION_PLACEHOLDER, indent=0)
|
|
103
|
+
|
|
104
|
+
def to_class_docstring(self, docstring_node: DocstringNode, indent: int) -> str:
|
|
105
|
+
"""
|
|
106
|
+
Convert an AST node into a class docstring.
|
|
107
|
+
|
|
108
|
+
Parameters
|
|
109
|
+
----------
|
|
110
|
+
docstring_node : DocstringNode
|
|
111
|
+
An instance of :class:`.DocstringNode`, which wraps an instance of
|
|
112
|
+
:class:`ast.ClassDef`, adding additional context relevant for Docstringify.
|
|
113
|
+
indent : int
|
|
114
|
+
The number of spaces by which to indent the docstring.
|
|
115
|
+
|
|
116
|
+
Returns
|
|
117
|
+
-------
|
|
118
|
+
str
|
|
119
|
+
The class docstring.
|
|
120
|
+
"""
|
|
121
|
+
return self.format_docstring(DESCRIPTION_PLACEHOLDER, indent=indent)
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
"""Docstringify exceptions."""
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
class EmptyDocstringError(ValueError):
|
|
5
|
+
"""
|
|
6
|
+
Raised when trying to write the modified source code back to a file if a docstring
|
|
7
|
+
is somehow empty.
|
|
8
|
+
"""
|
|
9
|
+
|
|
10
|
+
def __init__(self) -> None:
|
|
11
|
+
super().__init__('Docstring is empty')
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
class InvalidDocstringError(TypeError):
|
|
15
|
+
"""
|
|
16
|
+
Raised when trying to create a docstring with invalid input.
|
|
17
|
+
|
|
18
|
+
Parameters
|
|
19
|
+
----------
|
|
20
|
+
docstring_class : str
|
|
21
|
+
The class of the docstring object. This is used for the error message.
|
|
22
|
+
"""
|
|
23
|
+
|
|
24
|
+
def __init__(self, docstring_class: str) -> None:
|
|
25
|
+
super().__init__(f'Expected str or list[str] docstring, got {docstring_class}')
|
|
@@ -40,13 +40,15 @@ class DocstringNode:
|
|
|
40
40
|
) = node
|
|
41
41
|
self.name: str = getattr(node, 'name', self.module_name)
|
|
42
42
|
|
|
43
|
-
|
|
44
|
-
self.docstring = docstring if docstring is None else docstring.strip()
|
|
45
|
-
|
|
46
|
-
self.get_source_segment: Callable[[ast.AST], str] = partial(
|
|
43
|
+
self.get_source_segment: Callable[[ast.AST], str | None] = partial(
|
|
47
44
|
ast.get_source_segment, source_code
|
|
48
45
|
)
|
|
49
46
|
|
|
47
|
+
@property
|
|
48
|
+
def docstring(self) -> str | None:
|
|
49
|
+
docstring = ast.get_docstring(self.ast_node)
|
|
50
|
+
return docstring if docstring is None else docstring.strip()
|
|
51
|
+
|
|
50
52
|
@property
|
|
51
53
|
def fully_qualified_name(self) -> str:
|
|
52
54
|
return (
|
|
@@ -23,11 +23,17 @@ class FunctionDocstringNode(DocstringNode):
|
|
|
23
23
|
parent: DocstringNode,
|
|
24
24
|
) -> None:
|
|
25
25
|
super().__init__(node, module_name, source_code, parent)
|
|
26
|
+
|
|
26
27
|
self.decorators: list[str] = [
|
|
27
|
-
|
|
28
|
+
decorator
|
|
29
|
+
for decorator_node in node.decorator_list
|
|
30
|
+
if (decorator := self.get_source_segment(decorator_node))
|
|
28
31
|
]
|
|
29
32
|
|
|
30
|
-
self.
|
|
33
|
+
self.is_overload: bool = (
|
|
34
|
+
'overload' in self.decorators or 'typing.overload' in self.decorators
|
|
35
|
+
)
|
|
36
|
+
self.is_method: bool = self.parent is not None and isinstance(
|
|
31
37
|
self.parent.ast_node, ast.ClassDef
|
|
32
38
|
)
|
|
33
39
|
self.is_abstract_method: bool = self.is_method and (
|
|
@@ -39,15 +45,26 @@ class FunctionDocstringNode(DocstringNode):
|
|
|
39
45
|
self.is_method and 'staticmethod' in self.decorators
|
|
40
46
|
)
|
|
41
47
|
self.is_instance_method: bool = (
|
|
42
|
-
self.is_method
|
|
48
|
+
self.is_method
|
|
49
|
+
and (not self.is_class_method)
|
|
50
|
+
and (not self.is_static_method)
|
|
43
51
|
)
|
|
44
52
|
|
|
45
53
|
# don't require docstring for the __init__ method if the class has a docstring
|
|
46
|
-
|
|
47
|
-
|
|
54
|
+
# or if the function/method is just a typing.overload signature
|
|
55
|
+
self.docstring_required: bool = (
|
|
56
|
+
not (
|
|
57
|
+
self.is_method
|
|
58
|
+
and self.name == '__init__'
|
|
59
|
+
and self.parent is not None
|
|
60
|
+
and self.parent.docstring
|
|
61
|
+
)
|
|
62
|
+
and not self.is_overload
|
|
48
63
|
)
|
|
49
64
|
|
|
50
|
-
self.arguments: ast.arguments
|
|
65
|
+
self.arguments: ast.arguments = node.args
|
|
66
|
+
|
|
67
|
+
self.returns: ast.AST | None = node.returns
|
|
51
68
|
self.return_annotation: str | None = self._extract_return_annotation()
|
|
52
69
|
self.return_statements: list[ast.Return] = []
|
|
53
70
|
|
|
@@ -64,12 +81,23 @@ class FunctionDocstringNode(DocstringNode):
|
|
|
64
81
|
|
|
65
82
|
return (
|
|
66
83
|
f'"{default_value}"'
|
|
67
|
-
if isinstance(default_value, str)
|
|
84
|
+
if isinstance(default_value, str)
|
|
85
|
+
and (not default_value.startswith('`'))
|
|
68
86
|
else default_value
|
|
69
87
|
)
|
|
70
88
|
return NO_DEFAULT
|
|
71
89
|
|
|
72
|
-
def _extract_star_args(self) -> list[Parameter | None
|
|
90
|
+
def _extract_star_args(self) -> list[Parameter | None]:
|
|
91
|
+
"""
|
|
92
|
+
Extract the function's ``*args`` and ``**kwargs`` arguments.
|
|
93
|
+
|
|
94
|
+
Returns
|
|
95
|
+
-------
|
|
96
|
+
list[Parameter | None]
|
|
97
|
+
A list of the form ``[*args, **kwargs]``, where each entry is either a
|
|
98
|
+
:class:`.Parameter` instance, or ``None`` if that type of argument isn't
|
|
99
|
+
part of the function definition.
|
|
100
|
+
"""
|
|
73
101
|
return [
|
|
74
102
|
Parameter(
|
|
75
103
|
name=f'*{arg.arg}' if arg_type == 'vararg' else f'**{arg.arg}',
|
|
@@ -83,10 +111,11 @@ class FunctionDocstringNode(DocstringNode):
|
|
|
83
111
|
for arg in [getattr(self.arguments, arg_type)]
|
|
84
112
|
]
|
|
85
113
|
|
|
86
|
-
def _extract_positional_args(self) -> list[Parameter
|
|
114
|
+
def _extract_positional_args(self) -> list[Parameter]:
|
|
87
115
|
if (default_count := len(positional_defaults := self.arguments.defaults)) < (
|
|
88
|
-
positional_arguments_count :=
|
|
89
|
-
|
|
116
|
+
positional_arguments_count := (
|
|
117
|
+
len(self.arguments.posonlyargs) + len(self.arguments.args)
|
|
118
|
+
)
|
|
90
119
|
):
|
|
91
120
|
positional_defaults = [NO_DEFAULT] * (
|
|
92
121
|
positional_arguments_count - default_count
|
|
@@ -110,7 +139,7 @@ class FunctionDocstringNode(DocstringNode):
|
|
|
110
139
|
)
|
|
111
140
|
]
|
|
112
141
|
|
|
113
|
-
def _extract_keyword_args(self) -> list[Parameter
|
|
142
|
+
def _extract_keyword_args(self) -> list[Parameter]:
|
|
114
143
|
return [
|
|
115
144
|
Parameter(
|
|
116
145
|
name=arg.arg,
|
|
@@ -145,23 +174,28 @@ class FunctionDocstringNode(DocstringNode):
|
|
|
145
174
|
return params
|
|
146
175
|
|
|
147
176
|
def _extract_return_annotation(self) -> str | None:
|
|
148
|
-
if
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
177
|
+
if self.returns is None:
|
|
178
|
+
return self.returns
|
|
179
|
+
|
|
180
|
+
if isinstance(self.returns, ast.Constant):
|
|
181
|
+
return self.returns.value
|
|
182
|
+
|
|
183
|
+
if isinstance(self.returns, ast.Name):
|
|
184
|
+
return self.returns.id
|
|
185
|
+
|
|
186
|
+
return self.get_source_segment(self.returns)
|
|
155
187
|
|
|
156
188
|
def extract_returns(self) -> str | None:
|
|
157
189
|
if self.return_annotation:
|
|
158
190
|
return self.return_annotation
|
|
191
|
+
|
|
159
192
|
if any(
|
|
160
|
-
not isinstance(return_value := return_node.value, ast.Constant)
|
|
193
|
+
not isinstance((return_value := return_node.value), ast.Constant)
|
|
161
194
|
or return_value.value
|
|
162
195
|
for return_node in self.return_statements
|
|
163
196
|
):
|
|
164
197
|
return RETURN_TYPE_PLACEHOLDER
|
|
198
|
+
|
|
165
199
|
return None
|
|
166
200
|
|
|
167
201
|
def to_function(self) -> Function:
|
|
@@ -6,8 +6,10 @@ on the source code.
|
|
|
6
6
|
from __future__ import annotations
|
|
7
7
|
|
|
8
8
|
import ast
|
|
9
|
+
from textwrap import indent
|
|
9
10
|
from typing import TYPE_CHECKING
|
|
10
11
|
|
|
12
|
+
from ..exceptions import EmptyDocstringError
|
|
11
13
|
from .visitor import DocstringVisitor
|
|
12
14
|
|
|
13
15
|
if TYPE_CHECKING:
|
|
@@ -60,11 +62,80 @@ class DocstringTransformer(ast.NodeTransformer, DocstringVisitor):
|
|
|
60
62
|
+ ''.join(self.source_file.suffixes)
|
|
61
63
|
)
|
|
62
64
|
)
|
|
63
|
-
edited_code =
|
|
65
|
+
edited_code = self._convert_to_source_code()
|
|
64
66
|
output.write_text(edited_code)
|
|
65
67
|
print(f'Docstring templates written to {output}')
|
|
66
68
|
|
|
67
|
-
def
|
|
69
|
+
def _convert_to_source_code(self) -> str:
|
|
70
|
+
"""
|
|
71
|
+
Convert the modified AST back to source code, preserving the original format and
|
|
72
|
+
any comments.
|
|
73
|
+
|
|
74
|
+
Returns
|
|
75
|
+
-------
|
|
76
|
+
str
|
|
77
|
+
The original source code with the docstrings injected.
|
|
78
|
+
"""
|
|
79
|
+
source_code = self.source_code.splitlines()
|
|
80
|
+
output_lines = []
|
|
81
|
+
write_line = start_line = 0
|
|
82
|
+
|
|
83
|
+
for missing_docstring in self.missing_docstrings:
|
|
84
|
+
docstring_node = missing_docstring.ast_node.body[0]
|
|
85
|
+
prefix = docstring_node.col_offset
|
|
86
|
+
suffix = ''
|
|
87
|
+
|
|
88
|
+
# write everything before docstring
|
|
89
|
+
if not isinstance(missing_docstring.ast_node, ast.Module):
|
|
90
|
+
# line before a code node
|
|
91
|
+
start_line = missing_docstring.ast_node.body[1].lineno - 1
|
|
92
|
+
|
|
93
|
+
if isinstance(missing_docstring.ast_node, ast.ClassDef):
|
|
94
|
+
start_line = docstring_node.lineno
|
|
95
|
+
|
|
96
|
+
if len(body := missing_docstring.ast_node.body) == 2:
|
|
97
|
+
code_node = body[1]
|
|
98
|
+
line_number = code_node.lineno - 1
|
|
99
|
+
line = source_code[line_number]
|
|
100
|
+
|
|
101
|
+
if line.strip() != (function_body := line[code_node.col_offset :]):
|
|
102
|
+
# if the function body is on the same line as the signature, cut it out
|
|
103
|
+
# in order to inject the docstring in the right spot
|
|
104
|
+
source_code[line_number] = source_code[line_number][
|
|
105
|
+
: code_node.col_offset
|
|
106
|
+
].rstrip()
|
|
107
|
+
|
|
108
|
+
# add the logic under the docstring
|
|
109
|
+
start_line = missing_docstring.ast_node.body[1].lineno
|
|
110
|
+
suffix = function_body
|
|
111
|
+
|
|
112
|
+
output_lines += source_code[write_line:start_line]
|
|
113
|
+
|
|
114
|
+
# write docstring
|
|
115
|
+
if not (docstring := missing_docstring.docstring):
|
|
116
|
+
raise EmptyDocstringError
|
|
117
|
+
|
|
118
|
+
output_lines.append(
|
|
119
|
+
indent(
|
|
120
|
+
self.docstring_converter.format_docstring(
|
|
121
|
+
docstring.splitlines(),
|
|
122
|
+
indent=0,
|
|
123
|
+
quote=True,
|
|
124
|
+
)
|
|
125
|
+
+ (f'\n{suffix}' if suffix else ''),
|
|
126
|
+
' ' * prefix,
|
|
127
|
+
)
|
|
128
|
+
)
|
|
129
|
+
|
|
130
|
+
# update current location in file
|
|
131
|
+
write_line = start_line
|
|
132
|
+
|
|
133
|
+
# write the rest of the file
|
|
134
|
+
output_lines += source_code[write_line:]
|
|
135
|
+
|
|
136
|
+
return '\n'.join(output_lines) + '\n'
|
|
137
|
+
|
|
138
|
+
def handle_missing_docstring(self, docstring_node: DocstringNode) -> None:
|
|
68
139
|
"""
|
|
69
140
|
Handle missing docstrings by injecting a suggested docstring template based on
|
|
70
141
|
the source code into the AST.
|
|
@@ -74,19 +145,16 @@ class DocstringTransformer(ast.NodeTransformer, DocstringVisitor):
|
|
|
74
145
|
docstring_node : DocstringNode
|
|
75
146
|
An instance of :class:`.DocstringNode`, which wraps an AST node and adds
|
|
76
147
|
additional context relevant for Docstringify.
|
|
77
|
-
|
|
78
|
-
Returns
|
|
79
|
-
-------
|
|
80
|
-
DocstringNode
|
|
81
|
-
An instance of :class:`.DocstringNode`, which wraps an AST node and adds
|
|
82
|
-
additional context relevant for Docstringify. The AST node it contains will
|
|
83
|
-
have a new node for the docstring template added to its body.
|
|
84
148
|
"""
|
|
149
|
+
indent = (
|
|
150
|
+
0
|
|
151
|
+
if isinstance(docstring_node.ast_node, ast.Module)
|
|
152
|
+
else docstring_node.ast_node.col_offset + 4
|
|
153
|
+
)
|
|
154
|
+
|
|
85
155
|
suggested_docstring = self.docstring_converter.suggest_docstring(
|
|
86
156
|
docstring_node,
|
|
87
|
-
indent=
|
|
88
|
-
if isinstance(docstring_node.ast_node, ast.Module)
|
|
89
|
-
else docstring_node.ast_node.col_offset + 4,
|
|
157
|
+
indent=indent,
|
|
90
158
|
)
|
|
91
159
|
docstring_ast_node = ast.Expr(ast.Constant(suggested_docstring))
|
|
92
160
|
|
|
@@ -98,8 +166,7 @@ class DocstringTransformer(ast.NodeTransformer, DocstringVisitor):
|
|
|
98
166
|
docstring_node.ast_node.body.insert(0, docstring_ast_node)
|
|
99
167
|
|
|
100
168
|
docstring_node.ast_node = ast.fix_missing_locations(docstring_node.ast_node)
|
|
101
|
-
|
|
102
|
-
return docstring_node
|
|
169
|
+
docstring_ast_node.col_offset = indent
|
|
103
170
|
|
|
104
171
|
def process_file(self) -> None:
|
|
105
172
|
"""
|
|
@@ -8,7 +8,7 @@ from __future__ import annotations
|
|
|
8
8
|
import ast
|
|
9
9
|
import sys
|
|
10
10
|
from pathlib import Path
|
|
11
|
-
from typing import TYPE_CHECKING
|
|
11
|
+
from typing import TYPE_CHECKING, overload
|
|
12
12
|
|
|
13
13
|
from ..nodes.base import DocstringNode
|
|
14
14
|
from ..nodes.function import FunctionDocstringNode
|
|
@@ -112,8 +112,8 @@ class DocstringVisitor(ast.NodeVisitor):
|
|
|
112
112
|
|
|
113
113
|
def process_docstring(self, docstring_node: DocstringNode) -> DocstringNode:
|
|
114
114
|
"""
|
|
115
|
-
Process a docstring node, appending it to :attr:`.missing_docstrings` if a
|
|
116
|
-
is required, but there isn't one.
|
|
115
|
+
Process a docstring node, appending it to :attr:`.missing_docstrings` if a
|
|
116
|
+
docstring is required, but there isn't one.
|
|
117
117
|
|
|
118
118
|
Parameters
|
|
119
119
|
----------
|
|
@@ -133,6 +133,34 @@ class DocstringVisitor(ast.NodeVisitor):
|
|
|
133
133
|
self.docstrings_inspected += 1
|
|
134
134
|
return docstring_node
|
|
135
135
|
|
|
136
|
+
@overload
|
|
137
|
+
def visit_docstring(
|
|
138
|
+
self,
|
|
139
|
+
node: ast.Module,
|
|
140
|
+
docstring_class: type[DocstringNode],
|
|
141
|
+
) -> ast.Module: ...
|
|
142
|
+
|
|
143
|
+
@overload
|
|
144
|
+
def visit_docstring(
|
|
145
|
+
self,
|
|
146
|
+
node: ast.ClassDef,
|
|
147
|
+
docstring_class: type[DocstringNode],
|
|
148
|
+
) -> ast.ClassDef: ...
|
|
149
|
+
|
|
150
|
+
@overload
|
|
151
|
+
def visit_docstring(
|
|
152
|
+
self,
|
|
153
|
+
node: ast.FunctionDef,
|
|
154
|
+
docstring_class: type[FunctionDocstringNode],
|
|
155
|
+
) -> ast.FunctionDef: ...
|
|
156
|
+
|
|
157
|
+
@overload
|
|
158
|
+
def visit_docstring(
|
|
159
|
+
self,
|
|
160
|
+
node: ast.AsyncFunctionDef,
|
|
161
|
+
docstring_class: type[FunctionDocstringNode],
|
|
162
|
+
) -> ast.AsyncFunctionDef: ...
|
|
163
|
+
|
|
136
164
|
def visit_docstring(
|
|
137
165
|
self,
|
|
138
166
|
node: ast.AsyncFunctionDef | ast.ClassDef | ast.FunctionDef | ast.Module,
|
|
@@ -153,12 +181,12 @@ class DocstringVisitor(ast.NodeVisitor):
|
|
|
153
181
|
ast.AsyncFunctionDef | ast.ClassDef | ast.FunctionDef | ast.Module
|
|
154
182
|
The AST node that was visited.
|
|
155
183
|
"""
|
|
156
|
-
|
|
157
|
-
node,
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
184
|
+
if isinstance(node, ast.Module):
|
|
185
|
+
docstring_node = docstring_class(node, self.module_name, self.source_code)
|
|
186
|
+
else:
|
|
187
|
+
docstring_node = docstring_class(
|
|
188
|
+
node, self.module_name, self.source_code, parent=self.stack[-1]
|
|
189
|
+
)
|
|
162
190
|
|
|
163
191
|
self.stack.append(docstring_node)
|
|
164
192
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: docstringify
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 1.0.0
|
|
4
4
|
Summary: Flag missing docstrings and, optionally, generate them from signatures and type annotations.
|
|
5
5
|
Author-email: Stefanie Molin <docstringify@stefaniemolin.com>
|
|
6
6
|
License: MIT License
|
|
@@ -29,7 +29,7 @@ Project-URL: Documentation, https://github.com/stefmolin/docstringify
|
|
|
29
29
|
Project-URL: Homepage, https://github.com/stefmolin/docstringify
|
|
30
30
|
Project-URL: Source, https://github.com/stefmolin/docstringify
|
|
31
31
|
Keywords: ast,docstring generation,google-style docstring,numpydoc-style docstring,pre-commit
|
|
32
|
-
Classifier: Development Status ::
|
|
32
|
+
Classifier: Development Status :: 4 - Beta
|
|
33
33
|
Classifier: Programming Language :: Python
|
|
34
34
|
Classifier: Programming Language :: Python :: 3 :: Only
|
|
35
35
|
Classifier: Programming Language :: Python :: 3.9
|
|
@@ -103,11 +103,11 @@ You can use Docstringify in three modes:
|
|
|
103
103
|
|
|
104
104
|
### Pre-commit hook
|
|
105
105
|
|
|
106
|
-
Add the following to your `.pre-commit-config.yaml` file to block commits with missing docstrings
|
|
106
|
+
Add the following to your `.pre-commit-config.yaml` file to block commits with missing docstrings before any formatters like `ruff`:
|
|
107
107
|
|
|
108
108
|
```yaml
|
|
109
109
|
- repo: https://github.com/stefmolin/docstringify
|
|
110
|
-
rev: 0.
|
|
110
|
+
rev: 1.0.0
|
|
111
111
|
hooks:
|
|
112
112
|
- id: docstringify
|
|
113
113
|
```
|
|
@@ -116,17 +116,17 @@ By default, all docstrings are required. If you want to be more lenient, you can
|
|
|
116
116
|
|
|
117
117
|
```yaml
|
|
118
118
|
- repo: https://github.com/stefmolin/docstringify
|
|
119
|
-
rev: 0.
|
|
119
|
+
rev: 1.0.0
|
|
120
120
|
hooks:
|
|
121
121
|
- id: docstringify
|
|
122
122
|
args: [--threshold=0.75]
|
|
123
123
|
```
|
|
124
124
|
|
|
125
|
-
If you would like to see suggested docstring templates (inferred from type annotations for functions and methods), provide the `--suggest-changes` argument, along with the docstring style you want to use (options are `google` and `
|
|
125
|
+
If you would like to see suggested docstring templates (inferred from type annotations for functions and methods), provide the `--suggest-changes` argument, along with the docstring style you want to use (options are `google`, `numpydoc`, and `stub`). Here, we ask for stub suggestions (just single lines of `"""__description__"""`):
|
|
126
126
|
|
|
127
127
|
```yaml
|
|
128
128
|
- repo: https://github.com/stefmolin/docstringify
|
|
129
|
-
rev: 0.
|
|
129
|
+
rev: 1.0.0
|
|
130
130
|
hooks:
|
|
131
131
|
- id: docstringify
|
|
132
132
|
args: [--suggest-changes=numpydoc]
|
|
@@ -136,13 +136,21 @@ Use `--make-changes` to create a copy of each file with docstring templates. Her
|
|
|
136
136
|
|
|
137
137
|
```yaml
|
|
138
138
|
- repo: https://github.com/stefmolin/docstringify
|
|
139
|
-
rev: 0.
|
|
139
|
+
rev: 1.0.0
|
|
140
140
|
hooks:
|
|
141
141
|
- id: docstringify
|
|
142
142
|
args: [--make-changes=google]
|
|
143
143
|
```
|
|
144
144
|
|
|
145
|
-
If you want the changes to be made in place, change `--make-changes` to `--make-changes-inplace` – make sure you only operate on files that are in version control with this setting.
|
|
145
|
+
If you want the changes to be made in place, change `--make-changes` to `--make-changes-inplace` – make sure you only operate on files that are in version control with this setting. Here, we ask for [numpydoc-style docstring](https://numpydoc.readthedocs.io/en/latest/format.html#) suggestions:
|
|
146
|
+
|
|
147
|
+
```yaml
|
|
148
|
+
- repo: https://github.com/stefmolin/docstringify
|
|
149
|
+
rev: 1.0.0
|
|
150
|
+
hooks:
|
|
151
|
+
- id: docstringify
|
|
152
|
+
args: [--make-changes-inplace=numpydoc]
|
|
153
|
+
```
|
|
146
154
|
|
|
147
155
|
Be sure to check out the [pre-commit documentation](https://pre-commit.com/#pre-commit-configyaml---hooks) for additional configuration options.
|
|
148
156
|
|
|
@@ -216,7 +224,19 @@ test.say_hello is missing a docstring
|
|
|
216
224
|
Docstring templates written to /.../test_docstringify.py
|
|
217
225
|
```
|
|
218
226
|
|
|
219
|
-
If you want to overwrite the file with the edits, pass `overwrite=True` to `DocstringTransformer()
|
|
227
|
+
If you want to overwrite the file with the edits, pass `overwrite=True` to `DocstringTransformer()`:
|
|
228
|
+
|
|
229
|
+
```pycon
|
|
230
|
+
>>> from docstringify.converters import GoogleDocstringConverter
|
|
231
|
+
>>> from docstringify.traversal import DocstringTransformer
|
|
232
|
+
>>> transformer = DocstringTransformer(
|
|
233
|
+
... 'test.py', converter=GoogleDocstringConverter, overwrite=True
|
|
234
|
+
... )
|
|
235
|
+
>>> transformer.process_file()
|
|
236
|
+
test is missing a docstring
|
|
237
|
+
test.say_hello is missing a docstring
|
|
238
|
+
Docstring templates written to /.../test.py
|
|
239
|
+
```
|
|
220
240
|
|
|
221
241
|
## Contributing
|
|
222
242
|
|
|
@@ -29,6 +29,7 @@ src/docstringify/converters/__init__.py
|
|
|
29
29
|
src/docstringify/converters/base.py
|
|
30
30
|
src/docstringify/converters/google.py
|
|
31
31
|
src/docstringify/converters/numpydoc.py
|
|
32
|
+
src/docstringify/converters/stub.py
|
|
32
33
|
src/docstringify/nodes/__init__.py
|
|
33
34
|
src/docstringify/nodes/base.py
|
|
34
35
|
src/docstringify/nodes/function.py
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|