docstring-generator-ext 2.0.2__tar.gz → 2.0.3__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {docstring_generator_ext-2.0.2 → docstring_generator_ext-2.0.3}/PKG-INFO +84 -3
- {docstring_generator_ext-2.0.2 → docstring_generator_ext-2.0.3}/README.md +83 -2
- {docstring_generator_ext-2.0.2 → docstring_generator_ext-2.0.3}/docstring_generator_ext.egg-info/PKG-INFO +84 -3
- {docstring_generator_ext-2.0.2 → docstring_generator_ext-2.0.3}/pyproject.toml +1 -1
- {docstring_generator_ext-2.0.2 → docstring_generator_ext-2.0.3}/src/FunctionFormat.cpp +64 -0
- {docstring_generator_ext-2.0.2 → docstring_generator_ext-2.0.3}/src/FunctionFormat.hpp +13 -0
- {docstring_generator_ext-2.0.2 → docstring_generator_ext-2.0.3}/src/GoogleDocstring.cpp +20 -14
- {docstring_generator_ext-2.0.2 → docstring_generator_ext-2.0.3}/src/GoogleDocstring.hpp +1 -0
- {docstring_generator_ext-2.0.2 → docstring_generator_ext-2.0.3}/src/IDocstringFormat.cpp +0 -1
- {docstring_generator_ext-2.0.2 → docstring_generator_ext-2.0.3}/src/docstringFormat.cpp +66 -29
- {docstring_generator_ext-2.0.2 → docstring_generator_ext-2.0.3}/src/docstringFormat.hpp +11 -2
- {docstring_generator_ext-2.0.2 → docstring_generator_ext-2.0.3}/src/parser.cpp +22 -1
- {docstring_generator_ext-2.0.2 → docstring_generator_ext-2.0.3}/src/parser.hpp +1 -0
- {docstring_generator_ext-2.0.2 → docstring_generator_ext-2.0.3}/MANIFEST.in +0 -0
- {docstring_generator_ext-2.0.2 → docstring_generator_ext-2.0.3}/docstring_generator_ext.egg-info/SOURCES.txt +0 -0
- {docstring_generator_ext-2.0.2 → docstring_generator_ext-2.0.3}/docstring_generator_ext.egg-info/dependency_links.txt +0 -0
- {docstring_generator_ext-2.0.2 → docstring_generator_ext-2.0.3}/docstring_generator_ext.egg-info/requires.txt +0 -0
- {docstring_generator_ext-2.0.2 → docstring_generator_ext-2.0.3}/docstring_generator_ext.egg-info/top_level.txt +0 -0
- {docstring_generator_ext-2.0.2 → docstring_generator_ext-2.0.3}/setup.cfg +0 -0
- {docstring_generator_ext-2.0.2 → docstring_generator_ext-2.0.3}/setup.py +0 -0
- {docstring_generator_ext-2.0.2 → docstring_generator_ext-2.0.3}/src/IDocstringFormat.hpp +0 -0
- {docstring_generator_ext-2.0.2 → docstring_generator_ext-2.0.3}/src/NumpyDocstring.cpp +0 -0
- {docstring_generator_ext-2.0.2 → docstring_generator_ext-2.0.3}/src/NumpyDocstring.hpp +0 -0
- {docstring_generator_ext-2.0.2 → docstring_generator_ext-2.0.3}/src/ReStructuredDocstring.cpp +0 -0
- {docstring_generator_ext-2.0.2 → docstring_generator_ext-2.0.3}/src/ReStructuredDocstring.hpp +0 -0
- {docstring_generator_ext-2.0.2 → docstring_generator_ext-2.0.3}/src/docComparator.cpp +0 -0
- {docstring_generator_ext-2.0.2 → docstring_generator_ext-2.0.3}/src/docComparator.hpp +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: docstring_generator_ext
|
|
3
|
-
Version: 2.0.
|
|
3
|
+
Version: 2.0.3
|
|
4
4
|
Summary: Generate Docstrings with type-hint information.
|
|
5
5
|
Author-email: FelixTheC <fberndt87@gmail.com>
|
|
6
6
|
Classifier: Environment :: Console
|
|
@@ -25,13 +25,20 @@ Requires-Dist: pybind11>=3.0.4
|
|
|
25
25
|
## Features
|
|
26
26
|
|
|
27
27
|
- **Automatic Docstring Injection**: Parses Python files and inserts docstrings for functions and methods.
|
|
28
|
+
- **Async-function support**: Handles both `def` and `async def` functions transparently.
|
|
28
29
|
- **Type-Hint Awareness**: Extracts type information from annotations and default values.
|
|
29
30
|
- **Multiple Styles**: Supports popular docstring formats:
|
|
30
31
|
- **reST** (reStructuredText)
|
|
31
32
|
- **Google** style
|
|
32
33
|
- **NumPy** style
|
|
34
|
+
- **Format-style detection**: Automatically detects the style of an existing docstring and refuses to silently mix styles unless `allow_overwrite=True` is passed.
|
|
35
|
+
- **Style conversion**: With `allow_overwrite=True`, converts a docstring written in one style to another in a single call.
|
|
36
|
+
- **Exception detection**: Analyses the function body with Python's `ast` module to identify raised exceptions and include them in the docstring.
|
|
37
|
+
- **Docstring coverage auditing**: `check_docstring()` reports how many functions in a file have complete, partial, or missing docstrings without modifying the file.
|
|
33
38
|
- **High Performance**: Core logic implemented in C++ for fast processing.
|
|
34
|
-
- **Preserves Existing Content**:
|
|
39
|
+
- **Preserves Existing Content**: Keeps manually written descriptions across re-runs using special in-docstring markers:
|
|
40
|
+
- `$N` binds the text on that line to the *N*-th function parameter.
|
|
41
|
+
- `>>` provides the return-value description.
|
|
35
42
|
|
|
36
43
|
## Installation
|
|
37
44
|
|
|
@@ -81,7 +88,23 @@ style = docstring_generator_ext.DocstringFormatStyle.GOOGLE
|
|
|
81
88
|
docstring_generator_ext.parse_file(file_path, style)
|
|
82
89
|
```
|
|
83
90
|
|
|
84
|
-
|
|
91
|
+
### Overwriting an existing docstring format
|
|
92
|
+
|
|
93
|
+
By default, `parse_file` refuses to overwrite a docstring that was already written in a **different** style than the one you requested, and will print a warning instead. Pass `allow_overwrite=True` to let the extension convert the existing docstring to the new style:
|
|
94
|
+
|
|
95
|
+
```python
|
|
96
|
+
import docstring_generator_ext
|
|
97
|
+
|
|
98
|
+
file_path = "path/to/your_script.py"
|
|
99
|
+
style = docstring_generator_ext.DocstringFormatStyle.NUMPY
|
|
100
|
+
|
|
101
|
+
# Convert any existing docstring style to NUMPY — previous style will be removed
|
|
102
|
+
docstring_generator_ext.parse_file(file_path, style, allow_overwrite=True)
|
|
103
|
+
```
|
|
104
|
+
|
|
105
|
+
### Auditing docstring coverage
|
|
106
|
+
|
|
107
|
+
You can audit an existing file to see how well its functions are documented, without making any changes:
|
|
85
108
|
|
|
86
109
|
```python
|
|
87
110
|
import docstring_generator_ext
|
|
@@ -115,6 +138,64 @@ The extension provides an enum `DocstringFormatStyle` to choose the desired outp
|
|
|
115
138
|
- `docstring_generator_ext.DocstringFormatStyle.GOOGLE`
|
|
116
139
|
- `docstring_generator_ext.DocstringFormatStyle.NUMPY`
|
|
117
140
|
|
|
141
|
+
### Preserving descriptions with special markers
|
|
142
|
+
|
|
143
|
+
When the extension processes a file that already contains docstrings, it tries to keep manually written descriptions in place. Two marker conventions are supported:
|
|
144
|
+
|
|
145
|
+
#### `$N` — argument description markers
|
|
146
|
+
|
|
147
|
+
Place a `$` followed by the **1-based index** of the parameter inside the docstring to bind a free-form description to that argument. The marker and the text on its line are extracted and attached to the corresponding parameter; the `$N` line is then removed from the generated docstring.
|
|
148
|
+
|
|
149
|
+
```python
|
|
150
|
+
def add(a: int, b: int) -> int:
|
|
151
|
+
"""Add two numbers together.
|
|
152
|
+
|
|
153
|
+
$1 The first operand.
|
|
154
|
+
$2 The second operand.
|
|
155
|
+
"""
|
|
156
|
+
return a + b
|
|
157
|
+
```
|
|
158
|
+
|
|
159
|
+
After the next `parse_file` run the descriptions will be wired to `a` and `b` automatically.
|
|
160
|
+
|
|
161
|
+
```python
|
|
162
|
+
def add(a: int, b: int) -> int:
|
|
163
|
+
"""Add two numbers together.
|
|
164
|
+
|
|
165
|
+
Args:
|
|
166
|
+
a (int): The first operand.
|
|
167
|
+
b (int): The second operand.
|
|
168
|
+
Returns:
|
|
169
|
+
int
|
|
170
|
+
"""
|
|
171
|
+
return a + b
|
|
172
|
+
```
|
|
173
|
+
|
|
174
|
+
#### `>>` — return description marker
|
|
175
|
+
|
|
176
|
+
Place `>>` on its own line inside the docstring to provide the description for the return value. The text after `>>` on that line is extracted as the return description, and the marker line is removed.
|
|
177
|
+
|
|
178
|
+
```python
|
|
179
|
+
def square(x: int) -> int:
|
|
180
|
+
"""Square a number.
|
|
181
|
+
|
|
182
|
+
>> The squared value of x.
|
|
183
|
+
"""
|
|
184
|
+
return x * x
|
|
185
|
+
```
|
|
186
|
+
After the next `parse_file` run the descriptions will be wired to `Returns` description automatically.
|
|
187
|
+
```python
|
|
188
|
+
def square(x: int) -> int:
|
|
189
|
+
"""Square a number.
|
|
190
|
+
|
|
191
|
+
Args:
|
|
192
|
+
x (int):
|
|
193
|
+
Returns:
|
|
194
|
+
int: The squared value of x.
|
|
195
|
+
"""
|
|
196
|
+
return x * x
|
|
197
|
+
```
|
|
198
|
+
|
|
118
199
|
## C++20
|
|
119
200
|
|
|
120
201
|
The core of this extension is written in **C++20** to take full advantage of the modern standard's best algorithms and features:
|
|
@@ -11,13 +11,20 @@
|
|
|
11
11
|
## Features
|
|
12
12
|
|
|
13
13
|
- **Automatic Docstring Injection**: Parses Python files and inserts docstrings for functions and methods.
|
|
14
|
+
- **Async-function support**: Handles both `def` and `async def` functions transparently.
|
|
14
15
|
- **Type-Hint Awareness**: Extracts type information from annotations and default values.
|
|
15
16
|
- **Multiple Styles**: Supports popular docstring formats:
|
|
16
17
|
- **reST** (reStructuredText)
|
|
17
18
|
- **Google** style
|
|
18
19
|
- **NumPy** style
|
|
20
|
+
- **Format-style detection**: Automatically detects the style of an existing docstring and refuses to silently mix styles unless `allow_overwrite=True` is passed.
|
|
21
|
+
- **Style conversion**: With `allow_overwrite=True`, converts a docstring written in one style to another in a single call.
|
|
22
|
+
- **Exception detection**: Analyses the function body with Python's `ast` module to identify raised exceptions and include them in the docstring.
|
|
23
|
+
- **Docstring coverage auditing**: `check_docstring()` reports how many functions in a file have complete, partial, or missing docstrings without modifying the file.
|
|
19
24
|
- **High Performance**: Core logic implemented in C++ for fast processing.
|
|
20
|
-
- **Preserves Existing Content**:
|
|
25
|
+
- **Preserves Existing Content**: Keeps manually written descriptions across re-runs using special in-docstring markers:
|
|
26
|
+
- `$N` binds the text on that line to the *N*-th function parameter.
|
|
27
|
+
- `>>` provides the return-value description.
|
|
21
28
|
|
|
22
29
|
## Installation
|
|
23
30
|
|
|
@@ -67,7 +74,23 @@ style = docstring_generator_ext.DocstringFormatStyle.GOOGLE
|
|
|
67
74
|
docstring_generator_ext.parse_file(file_path, style)
|
|
68
75
|
```
|
|
69
76
|
|
|
70
|
-
|
|
77
|
+
### Overwriting an existing docstring format
|
|
78
|
+
|
|
79
|
+
By default, `parse_file` refuses to overwrite a docstring that was already written in a **different** style than the one you requested, and will print a warning instead. Pass `allow_overwrite=True` to let the extension convert the existing docstring to the new style:
|
|
80
|
+
|
|
81
|
+
```python
|
|
82
|
+
import docstring_generator_ext
|
|
83
|
+
|
|
84
|
+
file_path = "path/to/your_script.py"
|
|
85
|
+
style = docstring_generator_ext.DocstringFormatStyle.NUMPY
|
|
86
|
+
|
|
87
|
+
# Convert any existing docstring style to NUMPY — previous style will be removed
|
|
88
|
+
docstring_generator_ext.parse_file(file_path, style, allow_overwrite=True)
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
### Auditing docstring coverage
|
|
92
|
+
|
|
93
|
+
You can audit an existing file to see how well its functions are documented, without making any changes:
|
|
71
94
|
|
|
72
95
|
```python
|
|
73
96
|
import docstring_generator_ext
|
|
@@ -101,6 +124,64 @@ The extension provides an enum `DocstringFormatStyle` to choose the desired outp
|
|
|
101
124
|
- `docstring_generator_ext.DocstringFormatStyle.GOOGLE`
|
|
102
125
|
- `docstring_generator_ext.DocstringFormatStyle.NUMPY`
|
|
103
126
|
|
|
127
|
+
### Preserving descriptions with special markers
|
|
128
|
+
|
|
129
|
+
When the extension processes a file that already contains docstrings, it tries to keep manually written descriptions in place. Two marker conventions are supported:
|
|
130
|
+
|
|
131
|
+
#### `$N` — argument description markers
|
|
132
|
+
|
|
133
|
+
Place a `$` followed by the **1-based index** of the parameter inside the docstring to bind a free-form description to that argument. The marker and the text on its line are extracted and attached to the corresponding parameter; the `$N` line is then removed from the generated docstring.
|
|
134
|
+
|
|
135
|
+
```python
|
|
136
|
+
def add(a: int, b: int) -> int:
|
|
137
|
+
"""Add two numbers together.
|
|
138
|
+
|
|
139
|
+
$1 The first operand.
|
|
140
|
+
$2 The second operand.
|
|
141
|
+
"""
|
|
142
|
+
return a + b
|
|
143
|
+
```
|
|
144
|
+
|
|
145
|
+
After the next `parse_file` run the descriptions will be wired to `a` and `b` automatically.
|
|
146
|
+
|
|
147
|
+
```python
|
|
148
|
+
def add(a: int, b: int) -> int:
|
|
149
|
+
"""Add two numbers together.
|
|
150
|
+
|
|
151
|
+
Args:
|
|
152
|
+
a (int): The first operand.
|
|
153
|
+
b (int): The second operand.
|
|
154
|
+
Returns:
|
|
155
|
+
int
|
|
156
|
+
"""
|
|
157
|
+
return a + b
|
|
158
|
+
```
|
|
159
|
+
|
|
160
|
+
#### `>>` — return description marker
|
|
161
|
+
|
|
162
|
+
Place `>>` on its own line inside the docstring to provide the description for the return value. The text after `>>` on that line is extracted as the return description, and the marker line is removed.
|
|
163
|
+
|
|
164
|
+
```python
|
|
165
|
+
def square(x: int) -> int:
|
|
166
|
+
"""Square a number.
|
|
167
|
+
|
|
168
|
+
>> The squared value of x.
|
|
169
|
+
"""
|
|
170
|
+
return x * x
|
|
171
|
+
```
|
|
172
|
+
After the next `parse_file` run the descriptions will be wired to `Returns` description automatically.
|
|
173
|
+
```python
|
|
174
|
+
def square(x: int) -> int:
|
|
175
|
+
"""Square a number.
|
|
176
|
+
|
|
177
|
+
Args:
|
|
178
|
+
x (int):
|
|
179
|
+
Returns:
|
|
180
|
+
int: The squared value of x.
|
|
181
|
+
"""
|
|
182
|
+
return x * x
|
|
183
|
+
```
|
|
184
|
+
|
|
104
185
|
## C++20
|
|
105
186
|
|
|
106
187
|
The core of this extension is written in **C++20** to take full advantage of the modern standard's best algorithms and features:
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: docstring_generator_ext
|
|
3
|
-
Version: 2.0.
|
|
3
|
+
Version: 2.0.3
|
|
4
4
|
Summary: Generate Docstrings with type-hint information.
|
|
5
5
|
Author-email: FelixTheC <fberndt87@gmail.com>
|
|
6
6
|
Classifier: Environment :: Console
|
|
@@ -25,13 +25,20 @@ Requires-Dist: pybind11>=3.0.4
|
|
|
25
25
|
## Features
|
|
26
26
|
|
|
27
27
|
- **Automatic Docstring Injection**: Parses Python files and inserts docstrings for functions and methods.
|
|
28
|
+
- **Async-function support**: Handles both `def` and `async def` functions transparently.
|
|
28
29
|
- **Type-Hint Awareness**: Extracts type information from annotations and default values.
|
|
29
30
|
- **Multiple Styles**: Supports popular docstring formats:
|
|
30
31
|
- **reST** (reStructuredText)
|
|
31
32
|
- **Google** style
|
|
32
33
|
- **NumPy** style
|
|
34
|
+
- **Format-style detection**: Automatically detects the style of an existing docstring and refuses to silently mix styles unless `allow_overwrite=True` is passed.
|
|
35
|
+
- **Style conversion**: With `allow_overwrite=True`, converts a docstring written in one style to another in a single call.
|
|
36
|
+
- **Exception detection**: Analyses the function body with Python's `ast` module to identify raised exceptions and include them in the docstring.
|
|
37
|
+
- **Docstring coverage auditing**: `check_docstring()` reports how many functions in a file have complete, partial, or missing docstrings without modifying the file.
|
|
33
38
|
- **High Performance**: Core logic implemented in C++ for fast processing.
|
|
34
|
-
- **Preserves Existing Content**:
|
|
39
|
+
- **Preserves Existing Content**: Keeps manually written descriptions across re-runs using special in-docstring markers:
|
|
40
|
+
- `$N` binds the text on that line to the *N*-th function parameter.
|
|
41
|
+
- `>>` provides the return-value description.
|
|
35
42
|
|
|
36
43
|
## Installation
|
|
37
44
|
|
|
@@ -81,7 +88,23 @@ style = docstring_generator_ext.DocstringFormatStyle.GOOGLE
|
|
|
81
88
|
docstring_generator_ext.parse_file(file_path, style)
|
|
82
89
|
```
|
|
83
90
|
|
|
84
|
-
|
|
91
|
+
### Overwriting an existing docstring format
|
|
92
|
+
|
|
93
|
+
By default, `parse_file` refuses to overwrite a docstring that was already written in a **different** style than the one you requested, and will print a warning instead. Pass `allow_overwrite=True` to let the extension convert the existing docstring to the new style:
|
|
94
|
+
|
|
95
|
+
```python
|
|
96
|
+
import docstring_generator_ext
|
|
97
|
+
|
|
98
|
+
file_path = "path/to/your_script.py"
|
|
99
|
+
style = docstring_generator_ext.DocstringFormatStyle.NUMPY
|
|
100
|
+
|
|
101
|
+
# Convert any existing docstring style to NUMPY — previous style will be removed
|
|
102
|
+
docstring_generator_ext.parse_file(file_path, style, allow_overwrite=True)
|
|
103
|
+
```
|
|
104
|
+
|
|
105
|
+
### Auditing docstring coverage
|
|
106
|
+
|
|
107
|
+
You can audit an existing file to see how well its functions are documented, without making any changes:
|
|
85
108
|
|
|
86
109
|
```python
|
|
87
110
|
import docstring_generator_ext
|
|
@@ -115,6 +138,64 @@ The extension provides an enum `DocstringFormatStyle` to choose the desired outp
|
|
|
115
138
|
- `docstring_generator_ext.DocstringFormatStyle.GOOGLE`
|
|
116
139
|
- `docstring_generator_ext.DocstringFormatStyle.NUMPY`
|
|
117
140
|
|
|
141
|
+
### Preserving descriptions with special markers
|
|
142
|
+
|
|
143
|
+
When the extension processes a file that already contains docstrings, it tries to keep manually written descriptions in place. Two marker conventions are supported:
|
|
144
|
+
|
|
145
|
+
#### `$N` — argument description markers
|
|
146
|
+
|
|
147
|
+
Place a `$` followed by the **1-based index** of the parameter inside the docstring to bind a free-form description to that argument. The marker and the text on its line are extracted and attached to the corresponding parameter; the `$N` line is then removed from the generated docstring.
|
|
148
|
+
|
|
149
|
+
```python
|
|
150
|
+
def add(a: int, b: int) -> int:
|
|
151
|
+
"""Add two numbers together.
|
|
152
|
+
|
|
153
|
+
$1 The first operand.
|
|
154
|
+
$2 The second operand.
|
|
155
|
+
"""
|
|
156
|
+
return a + b
|
|
157
|
+
```
|
|
158
|
+
|
|
159
|
+
After the next `parse_file` run the descriptions will be wired to `a` and `b` automatically.
|
|
160
|
+
|
|
161
|
+
```python
|
|
162
|
+
def add(a: int, b: int) -> int:
|
|
163
|
+
"""Add two numbers together.
|
|
164
|
+
|
|
165
|
+
Args:
|
|
166
|
+
a (int): The first operand.
|
|
167
|
+
b (int): The second operand.
|
|
168
|
+
Returns:
|
|
169
|
+
int
|
|
170
|
+
"""
|
|
171
|
+
return a + b
|
|
172
|
+
```
|
|
173
|
+
|
|
174
|
+
#### `>>` — return description marker
|
|
175
|
+
|
|
176
|
+
Place `>>` on its own line inside the docstring to provide the description for the return value. The text after `>>` on that line is extracted as the return description, and the marker line is removed.
|
|
177
|
+
|
|
178
|
+
```python
|
|
179
|
+
def square(x: int) -> int:
|
|
180
|
+
"""Square a number.
|
|
181
|
+
|
|
182
|
+
>> The squared value of x.
|
|
183
|
+
"""
|
|
184
|
+
return x * x
|
|
185
|
+
```
|
|
186
|
+
After the next `parse_file` run the descriptions will be wired to `Returns` description automatically.
|
|
187
|
+
```python
|
|
188
|
+
def square(x: int) -> int:
|
|
189
|
+
"""Square a number.
|
|
190
|
+
|
|
191
|
+
Args:
|
|
192
|
+
x (int):
|
|
193
|
+
Returns:
|
|
194
|
+
int: The squared value of x.
|
|
195
|
+
"""
|
|
196
|
+
return x * x
|
|
197
|
+
```
|
|
198
|
+
|
|
118
199
|
## C++20
|
|
119
200
|
|
|
120
201
|
The core of this extension is written in **C++20** to take full advantage of the modern standard's best algorithms and features:
|
|
@@ -152,6 +152,70 @@ void FunctionInfo::update_descriptions(const DocstringFormatStyle &formatStyle)
|
|
|
152
152
|
}
|
|
153
153
|
}
|
|
154
154
|
|
|
155
|
+
void FunctionDocstring::detect_format_style() noexcept {
|
|
156
|
+
bool could_be_numpy = false;
|
|
157
|
+
bool could_be_google = false;
|
|
158
|
+
bool could_be_rest = false;
|
|
159
|
+
|
|
160
|
+
could_be_google = std::ranges::any_of(TypicalFormatStyle[1].second, [this](const auto &part) {
|
|
161
|
+
return docstring.find(part) != std::string::npos;
|
|
162
|
+
});
|
|
163
|
+
|
|
164
|
+
// Numpy uses `Returns` as the keyword for the return value description and Google uses `Returns:` as the keyword for the return value description
|
|
165
|
+
// so if it's not google, it could be numpy
|
|
166
|
+
if (!could_be_google)
|
|
167
|
+
could_be_numpy = std::ranges::any_of(TypicalFormatStyle[0].second, [this](const auto &part) {
|
|
168
|
+
return docstring.find(part) != std::string::npos;
|
|
169
|
+
});
|
|
170
|
+
|
|
171
|
+
could_be_rest = std::ranges::any_of(TypicalFormatStyle[2].second, [this](const auto &part) {
|
|
172
|
+
return docstring.find(part) != std::string::npos;
|
|
173
|
+
});
|
|
174
|
+
|
|
175
|
+
const int total = could_be_numpy + could_be_google + could_be_rest;
|
|
176
|
+
|
|
177
|
+
// this means we have multiple format styles in the docstring which should be avoided
|
|
178
|
+
// so we should not detect the format style
|
|
179
|
+
if (total > 1) {
|
|
180
|
+
detected_format_style = std::nullopt;
|
|
181
|
+
return;
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
if (could_be_numpy) {
|
|
185
|
+
detected_format_style = DocstringFormatStyle::NUMPY;
|
|
186
|
+
} else if (could_be_google) {
|
|
187
|
+
detected_format_style = DocstringFormatStyle::GOOGLE;
|
|
188
|
+
} else if (could_be_rest) {
|
|
189
|
+
detected_format_style = DocstringFormatStyle::reST;
|
|
190
|
+
}
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
[[nodiscard]] int FunctionDocstring::remove_old_format_style() noexcept {
|
|
194
|
+
if (!detected_format_style.has_value())
|
|
195
|
+
return -1;
|
|
196
|
+
|
|
197
|
+
const auto get_end_pos = [](std::string& _docstring, StyleSections sections) {
|
|
198
|
+
std::vector<size_t> res;
|
|
199
|
+
std::ranges::for_each(sections, [&](const auto& line) {
|
|
200
|
+
res.emplace_back(_docstring.find(line));
|
|
201
|
+
});
|
|
202
|
+
std::ranges::sort(res, std::less<>());
|
|
203
|
+
return res[0];
|
|
204
|
+
};
|
|
205
|
+
|
|
206
|
+
switch (*detected_format_style)
|
|
207
|
+
{
|
|
208
|
+
case DocstringFormatStyle::NUMPY:
|
|
209
|
+
return get_end_pos(docstring, TypicalFormatStyle[0].second);
|
|
210
|
+
case DocstringFormatStyle::GOOGLE:
|
|
211
|
+
return get_end_pos(docstring, TypicalFormatStyle[1].second);
|
|
212
|
+
case DocstringFormatStyle::reST:
|
|
213
|
+
return get_end_pos(docstring, TypicalFormatStyle[2].second);
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
return -1;
|
|
217
|
+
}
|
|
218
|
+
|
|
155
219
|
FunctionDocstring get_docstring(const py::object &obj, const py::module &ast_module) noexcept {
|
|
156
220
|
FunctionDocstring functionDocstring{};
|
|
157
221
|
|
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
#ifndef DOCSTRING_GENERATOR_EXT_FUNCTIONFORMAT_HPP
|
|
2
2
|
#define DOCSTRING_GENERATOR_EXT_FUNCTIONFORMAT_HPP
|
|
3
|
+
|
|
4
|
+
#include <map>
|
|
3
5
|
#include <set>
|
|
4
6
|
#include <string>
|
|
5
7
|
#include <vector>
|
|
@@ -21,6 +23,13 @@ enum class DocstringFormatStyle {
|
|
|
21
23
|
NUMPY
|
|
22
24
|
};
|
|
23
25
|
|
|
26
|
+
using StyleSections = std::array<std::string_view, 3>;
|
|
27
|
+
constexpr std::array<std::pair<std::string_view, StyleSections>, 3> TypicalFormatStyle = {{
|
|
28
|
+
{"numpy", {"Parameters\n", "Returns\n", "Raises\n"}},
|
|
29
|
+
{"google", {"Args:", "Returns:", "Raises:"}},
|
|
30
|
+
{"rest", {":param", ":returns:", ":raises"}}
|
|
31
|
+
}};
|
|
32
|
+
|
|
24
33
|
ParameterKind from_str(const std::string &kind);
|
|
25
34
|
std::ostream &operator<<(std::ostream &out, ParameterKind const &obj) noexcept;
|
|
26
35
|
|
|
@@ -47,6 +56,10 @@ struct FunctionDocstring {
|
|
|
47
56
|
uint32_t start_line{};
|
|
48
57
|
size_t end_line{};
|
|
49
58
|
std::string docstring;
|
|
59
|
+
std::optional<DocstringFormatStyle> detected_format_style {std::nullopt};
|
|
60
|
+
|
|
61
|
+
void detect_format_style() noexcept;
|
|
62
|
+
[[nodiscard]] int remove_old_format_style() noexcept;
|
|
50
63
|
};
|
|
51
64
|
|
|
52
65
|
FunctionDocstring get_docstring(const py::object &obj, const py::module &ast_module) noexcept;
|
|
@@ -17,6 +17,21 @@ void GoogleDocstring::check_current_docstring() noexcept {
|
|
|
17
17
|
}
|
|
18
18
|
}
|
|
19
19
|
|
|
20
|
+
std::string GoogleDocstring::cleanArgsDescription(const std::string &arg, const std::string &description) noexcept {
|
|
21
|
+
std::string res = std::string {description};
|
|
22
|
+
|
|
23
|
+
if (const auto startPos = description.find("Args:\n"); startPos < std::string::npos) {
|
|
24
|
+
res = res.substr(startPos, res.size() - startPos);
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
if (const auto startPos = res.find(arg); startPos < std::string::npos) {
|
|
28
|
+
const auto pos = startPos + arg.size() + 1;
|
|
29
|
+
res = res.substr(pos, res.size() - pos);
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
return res;
|
|
33
|
+
}
|
|
34
|
+
|
|
20
35
|
std::string GoogleDocstring::docstringArgs() noexcept {
|
|
21
36
|
auto current_py_tab = get_tabs();
|
|
22
37
|
|
|
@@ -56,7 +71,7 @@ std::string GoogleDocstring::docstringArgs() noexcept {
|
|
|
56
71
|
}
|
|
57
72
|
if (!val.description.empty()) {
|
|
58
73
|
result += ": ";
|
|
59
|
-
result += val.description;
|
|
74
|
+
result += cleanArgsDescription(val.name, val.description);
|
|
60
75
|
}
|
|
61
76
|
if (!val.default_value.empty()) {
|
|
62
77
|
result += " (default is ";
|
|
@@ -79,15 +94,10 @@ std::string GoogleDocstring::docstringReturn() noexcept {
|
|
|
79
94
|
|
|
80
95
|
if (!functionInfo.returns.description.empty() || !functionInfo.returns.type.empty()) {
|
|
81
96
|
result += "\n";
|
|
82
|
-
|
|
83
|
-
if (PY_TAB != current_py_tab) {
|
|
84
|
-
result += PY_TAB;
|
|
85
|
-
} else {
|
|
86
|
-
result += PY_TAB;
|
|
87
|
-
current_py_tab = PY_TAB + PY_TAB;
|
|
88
|
-
}
|
|
97
|
+
result += current_py_tab;
|
|
89
98
|
|
|
90
99
|
result += "Returns:\n";
|
|
100
|
+
current_py_tab += PY_TAB;
|
|
91
101
|
result += current_py_tab;
|
|
92
102
|
|
|
93
103
|
if (!functionInfo.returns.type.empty()) {
|
|
@@ -112,13 +122,9 @@ std::string GoogleDocstring::docstringExceptions() noexcept {
|
|
|
112
122
|
auto current_py_tab = get_tabs();
|
|
113
123
|
|
|
114
124
|
result += "\n";
|
|
125
|
+
result += current_py_tab;
|
|
115
126
|
|
|
116
|
-
|
|
117
|
-
result += PY_TAB;
|
|
118
|
-
} else {
|
|
119
|
-
result += PY_TAB;
|
|
120
|
-
current_py_tab = PY_TAB + PY_TAB;
|
|
121
|
-
}
|
|
127
|
+
current_py_tab += PY_TAB;
|
|
122
128
|
|
|
123
129
|
result += "Raises:\n";
|
|
124
130
|
result += current_py_tab;
|
|
@@ -8,6 +8,7 @@ struct GoogleDocstring : DocstringFormat {
|
|
|
8
8
|
std::string docstringArgs() noexcept override;
|
|
9
9
|
std::string docstringReturn() noexcept override;
|
|
10
10
|
std::string docstringExceptions() noexcept override;
|
|
11
|
+
std::string cleanArgsDescription(const std::string &arg, const std::string &description) noexcept;
|
|
11
12
|
};
|
|
12
13
|
|
|
13
14
|
|
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
#include "docstringFormat.hpp"
|
|
2
2
|
#include <algorithm>
|
|
3
|
-
#include <format>
|
|
4
3
|
#include <fstream>
|
|
5
4
|
#include <iostream>
|
|
6
5
|
#include <sstream>
|
|
@@ -17,13 +16,14 @@
|
|
|
17
16
|
|
|
18
17
|
namespace py = pybind11;
|
|
19
18
|
|
|
20
|
-
|
|
19
|
+
[[nodiscard]] WriteResult write_to_file_position(
|
|
21
20
|
std::vector<FunctionInfo> &&infos,
|
|
22
21
|
const std::string &file_path,
|
|
23
|
-
const DocstringFormatStyle &formatStyle
|
|
22
|
+
const DocstringFormatStyle &formatStyle,
|
|
23
|
+
const bool &allow_overwrite
|
|
24
24
|
) noexcept;
|
|
25
25
|
|
|
26
|
-
std::string
|
|
26
|
+
std::optional<std::string> read_file(const std::string &file_path) {
|
|
27
27
|
std::ifstream file(file_path, std::ios::binary);
|
|
28
28
|
std::string file_content{};
|
|
29
29
|
|
|
@@ -32,19 +32,18 @@ std::string read_file(const std::string &file_path) {
|
|
|
32
32
|
outsstream << file.rdbuf();
|
|
33
33
|
file_content = outsstream.str();
|
|
34
34
|
} else {
|
|
35
|
-
|
|
35
|
+
return std::nullopt;
|
|
36
36
|
}
|
|
37
37
|
|
|
38
38
|
return file_content;
|
|
39
39
|
}
|
|
40
40
|
|
|
41
|
-
|
|
41
|
+
std::vector<FunctionInfo> createFunctionInfos(const std::string &text, const DocstringFormatStyle &formatStyle) {
|
|
42
|
+
std::vector<FunctionInfo> infos{};
|
|
42
43
|
py::module ast_module = py::module_::import("ast");
|
|
43
|
-
py::object generator_result = ast_module.attr("walk")(ast_module.attr("parse")(
|
|
44
|
+
const py::object generator_result = ast_module.attr("walk")(ast_module.attr("parse")(text));
|
|
44
45
|
py::iterator iter = py::iter(generator_result);
|
|
45
46
|
|
|
46
|
-
std::vector<FunctionInfo> infos{};
|
|
47
|
-
|
|
48
47
|
for (auto &obj: iter) {
|
|
49
48
|
if (py::isinstance(obj, ast_module.attr("FunctionDef")) || py::isinstance(
|
|
50
49
|
obj,
|
|
@@ -53,9 +52,20 @@ void parse_file(std::string &file_path, DocstringFormatStyle &formatStyle) {
|
|
|
53
52
|
FunctionInfo function_info = analyze_function(obj, ast_module);
|
|
54
53
|
function_info.update_descriptions(formatStyle);
|
|
55
54
|
infos.emplace_back(function_info);
|
|
56
|
-
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
return infos;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
void parse_file(const std::string &file_path, const DocstringFormatStyle &formatStyle, const bool &allow_overwrite) {
|
|
62
|
+
const auto result = read_file(file_path);
|
|
63
|
+
if (!result.has_value()) {
|
|
64
|
+
throw py::value_error(file_path + " is not a valid path.");
|
|
57
65
|
}
|
|
58
66
|
|
|
67
|
+
std::vector<FunctionInfo> infos = createFunctionInfos(*result, formatStyle);
|
|
68
|
+
|
|
59
69
|
std::ranges::sort(
|
|
60
70
|
infos,
|
|
61
71
|
[](const FunctionInfo &left, const FunctionInfo &right) {
|
|
@@ -64,7 +74,21 @@ void parse_file(std::string &file_path, DocstringFormatStyle &formatStyle) {
|
|
|
64
74
|
);
|
|
65
75
|
|
|
66
76
|
#ifndef DRY_RUN
|
|
67
|
-
write_to_file_position(std::move(infos), file_path, formatStyle);
|
|
77
|
+
const auto res = write_to_file_position(std::move(infos), file_path, formatStyle, allow_overwrite);
|
|
78
|
+
switch (res) {
|
|
79
|
+
|
|
80
|
+
case SUCCESS:
|
|
81
|
+
break;
|
|
82
|
+
case FAILURE:
|
|
83
|
+
py::print("Could not write to file.");
|
|
84
|
+
break;
|
|
85
|
+
case FILE_NOT_FOUND:
|
|
86
|
+
py::print("Could not write to file.");
|
|
87
|
+
break;
|
|
88
|
+
case INVALID_FORMAT:
|
|
89
|
+
py::print("Aborting changes. A different docstring format was detected from what is specified.");
|
|
90
|
+
break;
|
|
91
|
+
}
|
|
68
92
|
#endif
|
|
69
93
|
}
|
|
70
94
|
|
|
@@ -111,10 +135,11 @@ std::map<std::string, int> check_docstrings(std::string &file_path) {
|
|
|
111
135
|
};
|
|
112
136
|
}
|
|
113
137
|
|
|
114
|
-
|
|
138
|
+
[[nodiscard]] WriteResult write_to_file_position(
|
|
115
139
|
std::vector<FunctionInfo> &&infos,
|
|
116
140
|
const std::string &file_path,
|
|
117
|
-
const DocstringFormatStyle &formatStyle
|
|
141
|
+
const DocstringFormatStyle &formatStyle,
|
|
142
|
+
const bool &allow_overwrite
|
|
118
143
|
) noexcept {
|
|
119
144
|
std::fstream file;
|
|
120
145
|
|
|
@@ -139,6 +164,17 @@ void write_to_file_position(
|
|
|
139
164
|
end_pos = val.docstring.end_line;
|
|
140
165
|
}
|
|
141
166
|
|
|
167
|
+
if (val.docstring.detected_format_style.has_value()) {
|
|
168
|
+
if (!allow_overwrite && *val.docstring.detected_format_style != formatStyle) {
|
|
169
|
+
return INVALID_FORMAT;
|
|
170
|
+
}
|
|
171
|
+
if (allow_overwrite && *val.docstring.detected_format_style != formatStyle) {
|
|
172
|
+
const auto pos = val.docstring.remove_old_format_style();
|
|
173
|
+
if (pos >= 0)
|
|
174
|
+
start_pos = pos;
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
|
|
142
178
|
if (start_pos < 0 || end_pos - 1 < 0) {
|
|
143
179
|
break;
|
|
144
180
|
}
|
|
@@ -165,25 +201,25 @@ void write_to_file_position(
|
|
|
165
201
|
lines.insert(lines.begin() + start_pos, docstring_format->docstring());
|
|
166
202
|
}
|
|
167
203
|
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
}
|
|
204
|
+
std::ofstream out_file(file_path);
|
|
205
|
+
if (!out_file.is_open()) {
|
|
206
|
+
py::print("Error: Unable to open file for writing.");
|
|
207
|
+
std::cerr << "Error: Unable to open file for writing.\n";
|
|
208
|
+
return FILE_NOT_FOUND;
|
|
209
|
+
}
|
|
175
210
|
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
}
|
|
211
|
+
std::string output;
|
|
212
|
+
output.reserve(lines.size() * 80); // rough estimate
|
|
213
|
+
for (const auto &line : lines) {
|
|
214
|
+
output += line;
|
|
215
|
+
if (line.empty() || line[line.size() - 1] != '\n') {
|
|
216
|
+
output += '\n';
|
|
183
217
|
}
|
|
184
|
-
out_file.write(output.data(), static_cast<std::streamsize>(output.size()));
|
|
185
|
-
out_file.close();
|
|
186
218
|
}
|
|
219
|
+
out_file.write(output.data(), static_cast<std::streamsize>(output.size()));
|
|
220
|
+
out_file.close();
|
|
221
|
+
|
|
222
|
+
return SUCCESS;
|
|
187
223
|
}
|
|
188
224
|
|
|
189
225
|
|
|
@@ -195,6 +231,7 @@ PYBIND11_MODULE(docstring_generator_ext, m) {
|
|
|
195
231
|
"A function that parses a file",
|
|
196
232
|
py::arg("file_path"),
|
|
197
233
|
py::arg("formatStyle"),
|
|
234
|
+
py::arg("allow_overwrite") = false,
|
|
198
235
|
"The file_path where automatically docstrings should be added.",
|
|
199
236
|
"In which style should the Docstring be written."
|
|
200
237
|
);
|
|
@@ -5,11 +5,20 @@
|
|
|
5
5
|
#include <string>
|
|
6
6
|
#include "FunctionFormat.hpp"
|
|
7
7
|
|
|
8
|
-
|
|
8
|
+
enum WriteResult {
|
|
9
|
+
SUCCESS,
|
|
10
|
+
FAILURE,
|
|
11
|
+
FILE_NOT_FOUND,
|
|
12
|
+
INVALID_FORMAT
|
|
13
|
+
};
|
|
14
|
+
|
|
15
|
+
[[nodiscard]] std::optional<std::string> read_file(const std::string &file_path);
|
|
9
16
|
|
|
10
17
|
void get_docstring_arg_descr(FunctionInfo &functionInfo) noexcept;
|
|
11
18
|
|
|
12
|
-
|
|
19
|
+
[[nodiscard]] std::vector<FunctionInfo> createFunctionInfos(const std::string &text, const DocstringFormatStyle &formatStyle);
|
|
20
|
+
|
|
21
|
+
void parse_file(const std::string &file_path, const DocstringFormatStyle &formatStyle, const bool &allow_overwrite = false);
|
|
13
22
|
|
|
14
23
|
/*
|
|
15
24
|
* {
|
|
@@ -349,6 +349,26 @@ void get_docstring_arg_descr(FunctionInfo &functionInfo) noexcept {
|
|
|
349
349
|
}
|
|
350
350
|
}
|
|
351
351
|
|
|
352
|
+
void get_docstring_return_descr(FunctionInfo &functionInfo) noexcept {
|
|
353
|
+
if (functionInfo.docstring.docstring.empty()) {
|
|
354
|
+
return;
|
|
355
|
+
}
|
|
356
|
+
|
|
357
|
+
if (functionInfo.returns.description.empty()) {
|
|
358
|
+
const auto iter = std::ranges::search(functionInfo.docstring.docstring, std::string_view(">>"));
|
|
359
|
+
if (iter.empty()) {
|
|
360
|
+
return;
|
|
361
|
+
}
|
|
362
|
+
|
|
363
|
+
const auto start = std::ranges::distance(functionInfo.docstring.docstring.begin(), iter.end());
|
|
364
|
+
const auto end = functionInfo.docstring.docstring.find('\n', start);
|
|
365
|
+
if (end != std::string::npos && start > 0) {
|
|
366
|
+
functionInfo.returns.description = functionInfo.docstring.docstring.substr(start, end - start);
|
|
367
|
+
functionInfo.docstring.docstring.erase(start - 2, functionInfo.returns.description.size() + 3); // 3 = '>>' + '\n'
|
|
368
|
+
}
|
|
369
|
+
}
|
|
370
|
+
}
|
|
371
|
+
|
|
352
372
|
void get_exception(
|
|
353
373
|
const pybind11::object &function_body,
|
|
354
374
|
py::module &ast_module,
|
|
@@ -448,6 +468,7 @@ FunctionInfo analyze_function(
|
|
|
448
468
|
auto offset = py::cast<uint32_t>(py::getattr(obj, "col_offset"));
|
|
449
469
|
|
|
450
470
|
FunctionDocstring doc_str = get_docstring(py::reinterpret_borrow<py::object>(obj), ast_module);
|
|
471
|
+
doc_str.detect_format_style();
|
|
451
472
|
|
|
452
473
|
auto returns = py::getattr(obj, "returns");
|
|
453
474
|
|
|
@@ -481,7 +502,7 @@ FunctionInfo analyze_function(
|
|
|
481
502
|
}
|
|
482
503
|
|
|
483
504
|
get_docstring_arg_descr(functionInfo);
|
|
484
|
-
|
|
505
|
+
get_docstring_return_descr(functionInfo);
|
|
485
506
|
|
|
486
507
|
return functionInfo;
|
|
487
508
|
}
|
|
@@ -39,6 +39,7 @@ std::vector<FunctionParameter> generate_function_parameters(
|
|
|
39
39
|
|
|
40
40
|
void get_docstring_arg_descr(FunctionInfo &functionInfo) noexcept;
|
|
41
41
|
|
|
42
|
+
void get_docstring_return_descr(FunctionInfo &functionInfo) noexcept;
|
|
42
43
|
|
|
43
44
|
void get_exception(
|
|
44
45
|
const pybind11::object &function_body,
|
|
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
|
{docstring_generator_ext-2.0.2 → docstring_generator_ext-2.0.3}/src/ReStructuredDocstring.cpp
RENAMED
|
File without changes
|
{docstring_generator_ext-2.0.2 → docstring_generator_ext-2.0.3}/src/ReStructuredDocstring.hpp
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|