google-docstring-parser 0.0.11__tar.gz → 0.0.12__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.
- google_docstring_parser-0.0.12/.gitignore +176 -0
- google_docstring_parser-0.0.12/.pre-commit-hooks.yaml +14 -0
- {google_docstring_parser-0.0.11 → google_docstring_parser-0.0.12}/PKG-INFO +43 -37
- {google_docstring_parser-0.0.11 → google_docstring_parser-0.0.12}/README.md +33 -25
- {google_docstring_parser-0.0.11 → google_docstring_parser-0.0.12}/google_docstring_parser/__init__.py +1 -0
- {google_docstring_parser-0.0.11 → google_docstring_parser-0.0.12}/google_docstring_parser/google_docstring_parser.py +80 -36
- {google_docstring_parser-0.0.11 → google_docstring_parser-0.0.12}/google_docstring_parser/type_validation.py +2 -2
- {google_docstring_parser-0.0.11 → google_docstring_parser-0.0.12}/pyproject.toml +31 -42
- google_docstring_parser-0.0.12/requirements-dev.txt +1 -0
- google_docstring_parser-0.0.12/tests/__init__.py +0 -0
- google_docstring_parser-0.0.12/tests/test_brackets_validation.py +184 -0
- google_docstring_parser-0.0.12/tests/test_docstring_checker/__init__.py +0 -0
- google_docstring_parser-0.0.12/tests/test_docstring_checker/test_check_docstrings.py +1032 -0
- google_docstring_parser-0.0.12/tests/test_docstring_checker/test_docstring_validation.py +278 -0
- google_docstring_parser-0.0.12/tests/test_docstring_checker/test_example_files.py +118 -0
- google_docstring_parser-0.0.12/tests/test_docstring_checker/test_malformed_docstrings.py +131 -0
- google_docstring_parser-0.0.12/tests/test_docstring_checker/test_valid_docstrings.py +75 -0
- google_docstring_parser-0.0.12/tests/test_multiline_returns.py +131 -0
- google_docstring_parser-0.0.12/tests/test_parser.py +248 -0
- google_docstring_parser-0.0.12/tests/test_references.py +403 -0
- google_docstring_parser-0.0.12/tests/test_type_validation.py +229 -0
- google_docstring_parser-0.0.12/tests/test_type_validation_edge_cases.py +175 -0
- google_docstring_parser-0.0.12/tools/README.md +138 -0
- {google_docstring_parser-0.0.11 → google_docstring_parser-0.0.12}/tools/__init__.py +1 -0
- {google_docstring_parser-0.0.11 → google_docstring_parser-0.0.12}/tools/check_docstrings.py +42 -34
- google_docstring_parser-0.0.11/google_docstring_parser.egg-info/PKG-INFO +0 -192
- google_docstring_parser-0.0.11/google_docstring_parser.egg-info/SOURCES.txt +0 -14
- google_docstring_parser-0.0.11/google_docstring_parser.egg-info/dependency_links.txt +0 -1
- google_docstring_parser-0.0.11/google_docstring_parser.egg-info/requires.txt +0 -5
- google_docstring_parser-0.0.11/google_docstring_parser.egg-info/top_level.txt +0 -2
- google_docstring_parser-0.0.11/setup.cfg +0 -4
- {google_docstring_parser-0.0.11 → google_docstring_parser-0.0.12}/LICENSE +0 -0
- {google_docstring_parser-0.0.11 → google_docstring_parser-0.0.12}/google_docstring_parser/py.typed +0 -0
|
@@ -0,0 +1,176 @@
|
|
|
1
|
+
# Byte-compiled / optimized / DLL files
|
|
2
|
+
__pycache__/
|
|
3
|
+
*.py[cod]
|
|
4
|
+
*$py.class
|
|
5
|
+
|
|
6
|
+
# C extensions
|
|
7
|
+
*.so
|
|
8
|
+
|
|
9
|
+
# Distribution / packaging
|
|
10
|
+
.Python
|
|
11
|
+
build/
|
|
12
|
+
develop-eggs/
|
|
13
|
+
dist/
|
|
14
|
+
downloads/
|
|
15
|
+
eggs/
|
|
16
|
+
.eggs/
|
|
17
|
+
lib/
|
|
18
|
+
lib64/
|
|
19
|
+
parts/
|
|
20
|
+
sdist/
|
|
21
|
+
var/
|
|
22
|
+
wheels/
|
|
23
|
+
share/python-wheels/
|
|
24
|
+
*.egg-info/
|
|
25
|
+
.installed.cfg
|
|
26
|
+
*.egg
|
|
27
|
+
MANIFEST
|
|
28
|
+
|
|
29
|
+
# PyInstaller
|
|
30
|
+
# Usually these files are written by a python script from a template
|
|
31
|
+
# before PyInstaller builds the exe, so as to inject date/other infos into it.
|
|
32
|
+
*.manifest
|
|
33
|
+
*.spec
|
|
34
|
+
|
|
35
|
+
# Installer logs
|
|
36
|
+
pip-log.txt
|
|
37
|
+
pip-delete-this-directory.txt
|
|
38
|
+
|
|
39
|
+
# Unit test / coverage reports
|
|
40
|
+
htmlcov/
|
|
41
|
+
.tox/
|
|
42
|
+
.nox/
|
|
43
|
+
.coverage
|
|
44
|
+
.coverage.*
|
|
45
|
+
.cache
|
|
46
|
+
nosetests.xml
|
|
47
|
+
coverage.xml
|
|
48
|
+
*.cover
|
|
49
|
+
*.py,cover
|
|
50
|
+
.hypothesis/
|
|
51
|
+
.pytest_cache/
|
|
52
|
+
cover/
|
|
53
|
+
|
|
54
|
+
# Translations
|
|
55
|
+
*.mo
|
|
56
|
+
*.pot
|
|
57
|
+
|
|
58
|
+
# Django stuff:
|
|
59
|
+
*.log
|
|
60
|
+
local_settings.py
|
|
61
|
+
db.sqlite3
|
|
62
|
+
db.sqlite3-journal
|
|
63
|
+
|
|
64
|
+
# Flask stuff:
|
|
65
|
+
instance/
|
|
66
|
+
.webassets-cache
|
|
67
|
+
|
|
68
|
+
# Scrapy stuff:
|
|
69
|
+
.scrapy
|
|
70
|
+
|
|
71
|
+
# Sphinx documentation
|
|
72
|
+
docs/_build/
|
|
73
|
+
|
|
74
|
+
# PyBuilder
|
|
75
|
+
.pybuilder/
|
|
76
|
+
target/
|
|
77
|
+
|
|
78
|
+
# Jupyter Notebook
|
|
79
|
+
.ipynb_checkpoints
|
|
80
|
+
|
|
81
|
+
# IPython
|
|
82
|
+
profile_default/
|
|
83
|
+
ipython_config.py
|
|
84
|
+
|
|
85
|
+
# pyenv
|
|
86
|
+
# For a library or package, you might want to ignore these files since the code is
|
|
87
|
+
# intended to run in multiple environments; otherwise, check them in:
|
|
88
|
+
# .python-version
|
|
89
|
+
|
|
90
|
+
# pipenv
|
|
91
|
+
# According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control.
|
|
92
|
+
# However, in case of collaboration, if having platform-specific dependencies or dependencies
|
|
93
|
+
# having no cross-platform support, pipenv may install dependencies that don't work, or not
|
|
94
|
+
# install all needed dependencies.
|
|
95
|
+
#Pipfile.lock
|
|
96
|
+
|
|
97
|
+
# UV
|
|
98
|
+
# Similar to Pipfile.lock, it is generally recommended to include uv.lock in version control.
|
|
99
|
+
# This is especially recommended for binary packages to ensure reproducibility, and is more
|
|
100
|
+
# commonly ignored for libraries.
|
|
101
|
+
#uv.lock
|
|
102
|
+
|
|
103
|
+
# poetry
|
|
104
|
+
# Similar to Pipfile.lock, it is generally recommended to include poetry.lock in version control.
|
|
105
|
+
# This is especially recommended for binary packages to ensure reproducibility, and is more
|
|
106
|
+
# commonly ignored for libraries.
|
|
107
|
+
# https://python-poetry.org/docs/basic-usage/#commit-your-poetrylock-file-to-version-control
|
|
108
|
+
#poetry.lock
|
|
109
|
+
|
|
110
|
+
# pdm
|
|
111
|
+
# Similar to Pipfile.lock, it is generally recommended to include pdm.lock in version control.
|
|
112
|
+
#pdm.lock
|
|
113
|
+
# pdm stores project-wide configurations in .pdm.toml, but it is recommended to not include it
|
|
114
|
+
# in version control.
|
|
115
|
+
# https://pdm.fming.dev/latest/usage/project/#working-with-version-control
|
|
116
|
+
.pdm.toml
|
|
117
|
+
.pdm-python
|
|
118
|
+
.pdm-build/
|
|
119
|
+
|
|
120
|
+
# PEP 582; used by e.g. github.com/David-OConnor/pyflow and github.com/pdm-project/pdm
|
|
121
|
+
__pypackages__/
|
|
122
|
+
|
|
123
|
+
# Celery stuff
|
|
124
|
+
celerybeat-schedule
|
|
125
|
+
celerybeat.pid
|
|
126
|
+
|
|
127
|
+
# SageMath parsed files
|
|
128
|
+
*.sage.py
|
|
129
|
+
|
|
130
|
+
# Environments
|
|
131
|
+
.env
|
|
132
|
+
.venv
|
|
133
|
+
env/
|
|
134
|
+
venv/
|
|
135
|
+
ENV/
|
|
136
|
+
env.bak/
|
|
137
|
+
venv.bak/
|
|
138
|
+
|
|
139
|
+
# Spyder project settings
|
|
140
|
+
.spyderproject
|
|
141
|
+
.spyproject
|
|
142
|
+
|
|
143
|
+
# Rope project settings
|
|
144
|
+
.ropeproject
|
|
145
|
+
|
|
146
|
+
# mkdocs documentation
|
|
147
|
+
/site
|
|
148
|
+
|
|
149
|
+
# mypy
|
|
150
|
+
.mypy_cache/
|
|
151
|
+
.dmypy.json
|
|
152
|
+
dmypy.json
|
|
153
|
+
|
|
154
|
+
# Pyre type checker
|
|
155
|
+
.pyre/
|
|
156
|
+
|
|
157
|
+
# pytype static type analyzer
|
|
158
|
+
.pytype/
|
|
159
|
+
|
|
160
|
+
# Cython debug symbols
|
|
161
|
+
cython_debug/
|
|
162
|
+
|
|
163
|
+
# PyCharm
|
|
164
|
+
# JetBrains specific template is maintained in a separate JetBrains.gitignore that can
|
|
165
|
+
# be found at https://github.com/github/gitignore/blob/main/Global/JetBrains.gitignore
|
|
166
|
+
# and can be added to the global gitignore or merged into this file. For a more nuclear
|
|
167
|
+
# option (not recommended) you can uncomment the following to ignore the entire idea folder.
|
|
168
|
+
#.idea/
|
|
169
|
+
|
|
170
|
+
# Ruff stuff:
|
|
171
|
+
.ruff_cache/
|
|
172
|
+
|
|
173
|
+
# PyPI configuration file
|
|
174
|
+
.pypirc
|
|
175
|
+
|
|
176
|
+
uv.lock
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
- id: check-google-docstrings
|
|
2
|
+
name: Check Google-style docstrings can be parsed
|
|
3
|
+
description: >
|
|
4
|
+
Checks that Google-style docstrings in specified folders can be parsed with google_docstring_parser.
|
|
5
|
+
IMPORTANT: You MUST configure paths in pyproject.toml under [tool.docstring_checker] section,
|
|
6
|
+
otherwise no files will be checked. For example:
|
|
7
|
+
[tool.docstring_checker]
|
|
8
|
+
paths = ["your_package", "your_module"]
|
|
9
|
+
entry: python -m tools.check_docstrings
|
|
10
|
+
language: python
|
|
11
|
+
types: [python]
|
|
12
|
+
pass_filenames: false
|
|
13
|
+
require_serial: true
|
|
14
|
+
args: [] # Default empty args
|
|
@@ -1,36 +1,34 @@
|
|
|
1
|
-
Metadata-Version: 2.
|
|
1
|
+
Metadata-Version: 2.5
|
|
2
2
|
Name: google-docstring-parser
|
|
3
|
-
Version: 0.0.
|
|
3
|
+
Version: 0.0.12
|
|
4
4
|
Summary: A lightweight, efficient parser for Google-style Python docstrings that converts them into structured dictionaries.
|
|
5
5
|
Author: Vladimir Iglovikov
|
|
6
6
|
Maintainer: Vladimir Iglovikov
|
|
7
|
-
License:
|
|
7
|
+
License-Expression: LicenseRef-Proprietary
|
|
8
|
+
License-File: LICENSE
|
|
8
9
|
Keywords: docstring,documentation,google-style,parser,python,static-analysis,type-hints
|
|
9
10
|
Classifier: Development Status :: 5 - Production/Stable
|
|
10
11
|
Classifier: Intended Audience :: Developers
|
|
11
12
|
Classifier: Intended Audience :: Science/Research
|
|
12
|
-
Classifier: License :: Other/Proprietary License
|
|
13
13
|
Classifier: Operating System :: OS Independent
|
|
14
14
|
Classifier: Programming Language :: Python
|
|
15
15
|
Classifier: Programming Language :: Python :: 3 :: Only
|
|
16
|
-
Classifier: Programming Language :: Python :: 3.10
|
|
17
16
|
Classifier: Programming Language :: Python :: 3.11
|
|
18
17
|
Classifier: Programming Language :: Python :: 3.12
|
|
19
18
|
Classifier: Programming Language :: Python :: 3.13
|
|
20
19
|
Classifier: Programming Language :: Python :: 3.14
|
|
20
|
+
Classifier: Programming Language :: Python :: 3.15
|
|
21
21
|
Classifier: Topic :: Scientific/Engineering :: Artificial Intelligence
|
|
22
22
|
Classifier: Topic :: Software Development :: Documentation
|
|
23
23
|
Classifier: Topic :: Software Development :: Libraries
|
|
24
24
|
Classifier: Topic :: Software Development :: Libraries :: Python Modules
|
|
25
25
|
Classifier: Typing :: Typed
|
|
26
|
-
Requires-Python: >=3.
|
|
27
|
-
|
|
28
|
-
License-File: LICENSE
|
|
29
|
-
Requires-Dist: docstring-parser>=0.16
|
|
26
|
+
Requires-Python: >=3.11
|
|
27
|
+
Requires-Dist: docstring-parser>=0.18
|
|
30
28
|
Provides-Extra: dev
|
|
31
|
-
Requires-Dist: pre-commit>=
|
|
32
|
-
Requires-Dist: pytest>=
|
|
33
|
-
|
|
29
|
+
Requires-Dist: pre-commit>=4.7; extra == 'dev'
|
|
30
|
+
Requires-Dist: pytest>=9.2; extra == 'dev'
|
|
31
|
+
Description-Content-Type: text/markdown
|
|
34
32
|
|
|
35
33
|
# Google Docstring Parser
|
|
36
34
|
|
|
@@ -40,6 +38,8 @@ Dynamic: license-file
|
|
|
40
38
|
|
|
41
39
|
A Python package for parsing Google-style docstrings into structured dictionaries.
|
|
42
40
|
|
|
41
|
+
Requires Python 3.11 or newer.
|
|
42
|
+
|
|
43
43
|
## License Information
|
|
44
44
|
|
|
45
45
|
This package is available under a custom license:
|
|
@@ -59,7 +59,7 @@ pip install google-docstring-parser
|
|
|
59
59
|
```python
|
|
60
60
|
from google_docstring_parser import parse_google_docstring
|
|
61
61
|
|
|
62
|
-
docstring =
|
|
62
|
+
docstring = """Apply elastic deformation to images, masks, bounding boxes, and keypoints.
|
|
63
63
|
|
|
64
64
|
This transformation introduces random elastic distortions to the input data. It's particularly
|
|
65
65
|
useful for data augmentation in training deep learning models, especially for tasks like
|
|
@@ -81,7 +81,7 @@ References:
|
|
|
81
81
|
- Implementation details: https://example.com/elastic-transform
|
|
82
82
|
Returns:
|
|
83
83
|
dict[str, Any]: Some info here
|
|
84
|
-
|
|
84
|
+
"""
|
|
85
85
|
|
|
86
86
|
parsed = parse_google_docstring(docstring)
|
|
87
87
|
print(parsed)
|
|
@@ -90,35 +90,28 @@ print(parsed)
|
|
|
90
90
|
Output:
|
|
91
91
|
```python
|
|
92
92
|
{
|
|
93
|
-
|
|
94
|
-
|
|
93
|
+
"Description": "Apply elastic deformation to images, masks, bounding boxes, and keypoints.\n\nThis transformation introduces random elastic distortions to the input data. It's particularly\nuseful for data augmentation in training deep learning models, especially for tasks like\nimage segmentation or object detection where you want to maintain the relative positions of\nfeatures while introducing realistic deformations.",
|
|
94
|
+
"Args": [
|
|
95
95
|
{
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
96
|
+
"name": "alpha",
|
|
97
|
+
"type": "float",
|
|
98
|
+
"description": "Scaling factor for the random displacement fields. Higher values result in\nmore pronounced distortions. Default: 1.0",
|
|
99
99
|
},
|
|
100
100
|
{
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
}
|
|
101
|
+
"name": "sigma",
|
|
102
|
+
"type": "float",
|
|
103
|
+
"description": "Standard deviation of the Gaussian filter used to smooth the displacement\nfields. Higher values result in smoother, more global distortions. Default: 50.0",
|
|
104
|
+
},
|
|
105
105
|
],
|
|
106
|
-
|
|
107
|
-
|
|
106
|
+
"Example": ">>> import albumentations as A\n>>> transform = A.ElasticTransform(alpha=1, sigma=50, p=0.5)",
|
|
107
|
+
"References": [
|
|
108
108
|
{
|
|
109
|
-
|
|
110
|
-
|
|
109
|
+
"description": "Original paper",
|
|
110
|
+
"source": 'Simard, P. Y., et al. "Best practices for convolutional neural networks applied to visual document analysis." ICDAR 2003',
|
|
111
111
|
},
|
|
112
|
-
{
|
|
113
|
-
'description': 'Implementation details',
|
|
114
|
-
'source': 'https://example.com/elastic-transform'
|
|
115
|
-
}
|
|
112
|
+
{"description": "Implementation details", "source": "https://example.com/elastic-transform"},
|
|
116
113
|
],
|
|
117
|
-
|
|
118
|
-
{
|
|
119
|
-
"type": "dict[str, Any]",
|
|
120
|
-
"description": "Some info here"
|
|
121
|
-
}
|
|
114
|
+
"Returns": {"type": "dict[str, Any]", "description": "Some info here"},
|
|
122
115
|
}
|
|
123
116
|
```
|
|
124
117
|
|
|
@@ -130,6 +123,20 @@ Output:
|
|
|
130
123
|
- Handles multi-line descriptions and indentation properly
|
|
131
124
|
- Properly parses and validates References sections with special handling for URLs
|
|
132
125
|
|
|
126
|
+
### Wrapped return annotations
|
|
127
|
+
|
|
128
|
+
Long return types can span several lines. The parser accepts wrapped unions, generics, and parenthesized types:
|
|
129
|
+
|
|
130
|
+
```text
|
|
131
|
+
Returns:
|
|
132
|
+
dict[
|
|
133
|
+
str,
|
|
134
|
+
list[int | str],
|
|
135
|
+
]: Results grouped by name.
|
|
136
|
+
```
|
|
137
|
+
|
|
138
|
+
The parsed type is `dict[str, list[int | str]]`. Quoted colons and brackets inside `Literal` values are preserved, and wrapped prose remains untyped. The checker compares type expressions while preserving spaces inside literal values.
|
|
139
|
+
|
|
133
140
|
### References
|
|
134
141
|
|
|
135
142
|
The parser can handle reference sections in Google-style docstrings. References can be formatted in two ways:
|
|
@@ -170,7 +177,6 @@ To use this hook in another project, add the following to your `.pre-commit-conf
|
|
|
170
177
|
rev: v0.0.1 # Use the latest version
|
|
171
178
|
hooks:
|
|
172
179
|
- id: check-google-docstrings
|
|
173
|
-
additional_dependencies: ["tomli>=2.0.0"] # Required for pyproject.toml configuration
|
|
174
180
|
```
|
|
175
181
|
|
|
176
182
|
### Configuration
|
|
@@ -6,6 +6,8 @@
|
|
|
6
6
|
|
|
7
7
|
A Python package for parsing Google-style docstrings into structured dictionaries.
|
|
8
8
|
|
|
9
|
+
Requires Python 3.11 or newer.
|
|
10
|
+
|
|
9
11
|
## License Information
|
|
10
12
|
|
|
11
13
|
This package is available under a custom license:
|
|
@@ -25,7 +27,7 @@ pip install google-docstring-parser
|
|
|
25
27
|
```python
|
|
26
28
|
from google_docstring_parser import parse_google_docstring
|
|
27
29
|
|
|
28
|
-
docstring =
|
|
30
|
+
docstring = """Apply elastic deformation to images, masks, bounding boxes, and keypoints.
|
|
29
31
|
|
|
30
32
|
This transformation introduces random elastic distortions to the input data. It's particularly
|
|
31
33
|
useful for data augmentation in training deep learning models, especially for tasks like
|
|
@@ -47,7 +49,7 @@ References:
|
|
|
47
49
|
- Implementation details: https://example.com/elastic-transform
|
|
48
50
|
Returns:
|
|
49
51
|
dict[str, Any]: Some info here
|
|
50
|
-
|
|
52
|
+
"""
|
|
51
53
|
|
|
52
54
|
parsed = parse_google_docstring(docstring)
|
|
53
55
|
print(parsed)
|
|
@@ -56,35 +58,28 @@ print(parsed)
|
|
|
56
58
|
Output:
|
|
57
59
|
```python
|
|
58
60
|
{
|
|
59
|
-
|
|
60
|
-
|
|
61
|
+
"Description": "Apply elastic deformation to images, masks, bounding boxes, and keypoints.\n\nThis transformation introduces random elastic distortions to the input data. It's particularly\nuseful for data augmentation in training deep learning models, especially for tasks like\nimage segmentation or object detection where you want to maintain the relative positions of\nfeatures while introducing realistic deformations.",
|
|
62
|
+
"Args": [
|
|
61
63
|
{
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
64
|
+
"name": "alpha",
|
|
65
|
+
"type": "float",
|
|
66
|
+
"description": "Scaling factor for the random displacement fields. Higher values result in\nmore pronounced distortions. Default: 1.0",
|
|
65
67
|
},
|
|
66
68
|
{
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
}
|
|
69
|
+
"name": "sigma",
|
|
70
|
+
"type": "float",
|
|
71
|
+
"description": "Standard deviation of the Gaussian filter used to smooth the displacement\nfields. Higher values result in smoother, more global distortions. Default: 50.0",
|
|
72
|
+
},
|
|
71
73
|
],
|
|
72
|
-
|
|
73
|
-
|
|
74
|
+
"Example": ">>> import albumentations as A\n>>> transform = A.ElasticTransform(alpha=1, sigma=50, p=0.5)",
|
|
75
|
+
"References": [
|
|
74
76
|
{
|
|
75
|
-
|
|
76
|
-
|
|
77
|
+
"description": "Original paper",
|
|
78
|
+
"source": 'Simard, P. Y., et al. "Best practices for convolutional neural networks applied to visual document analysis." ICDAR 2003',
|
|
77
79
|
},
|
|
78
|
-
{
|
|
79
|
-
'description': 'Implementation details',
|
|
80
|
-
'source': 'https://example.com/elastic-transform'
|
|
81
|
-
}
|
|
80
|
+
{"description": "Implementation details", "source": "https://example.com/elastic-transform"},
|
|
82
81
|
],
|
|
83
|
-
|
|
84
|
-
{
|
|
85
|
-
"type": "dict[str, Any]",
|
|
86
|
-
"description": "Some info here"
|
|
87
|
-
}
|
|
82
|
+
"Returns": {"type": "dict[str, Any]", "description": "Some info here"},
|
|
88
83
|
}
|
|
89
84
|
```
|
|
90
85
|
|
|
@@ -96,6 +91,20 @@ Output:
|
|
|
96
91
|
- Handles multi-line descriptions and indentation properly
|
|
97
92
|
- Properly parses and validates References sections with special handling for URLs
|
|
98
93
|
|
|
94
|
+
### Wrapped return annotations
|
|
95
|
+
|
|
96
|
+
Long return types can span several lines. The parser accepts wrapped unions, generics, and parenthesized types:
|
|
97
|
+
|
|
98
|
+
```text
|
|
99
|
+
Returns:
|
|
100
|
+
dict[
|
|
101
|
+
str,
|
|
102
|
+
list[int | str],
|
|
103
|
+
]: Results grouped by name.
|
|
104
|
+
```
|
|
105
|
+
|
|
106
|
+
The parsed type is `dict[str, list[int | str]]`. Quoted colons and brackets inside `Literal` values are preserved, and wrapped prose remains untyped. The checker compares type expressions while preserving spaces inside literal values.
|
|
107
|
+
|
|
99
108
|
### References
|
|
100
109
|
|
|
101
110
|
The parser can handle reference sections in Google-style docstrings. References can be formatted in two ways:
|
|
@@ -136,7 +145,6 @@ To use this hook in another project, add the following to your `.pre-commit-conf
|
|
|
136
145
|
rev: v0.0.1 # Use the latest version
|
|
137
146
|
hooks:
|
|
138
147
|
- id: check-google-docstrings
|
|
139
|
-
additional_dependencies: ["tomli>=2.0.0"] # Required for pyproject.toml configuration
|
|
140
148
|
```
|
|
141
149
|
|
|
142
150
|
### Configuration
|
|
@@ -18,7 +18,10 @@ This module provides functions to parse Google-style docstrings into structured
|
|
|
18
18
|
|
|
19
19
|
from __future__ import annotations
|
|
20
20
|
|
|
21
|
+
import ast
|
|
22
|
+
import io
|
|
21
23
|
import re
|
|
24
|
+
import tokenize
|
|
22
25
|
from typing import TYPE_CHECKING, Any
|
|
23
26
|
|
|
24
27
|
from docstring_parser import parse
|
|
@@ -438,42 +441,86 @@ def _process_args_with_validation(
|
|
|
438
441
|
result["Args"] = args
|
|
439
442
|
|
|
440
443
|
|
|
441
|
-
def
|
|
442
|
-
"""
|
|
444
|
+
def _return_annotation_tokens(text: str) -> tuple[list[tuple[int, str]], tuple[int, int] | None]:
|
|
445
|
+
"""Find the return separator outside quoted literals and nested brackets.
|
|
443
446
|
|
|
444
447
|
Args:
|
|
445
|
-
|
|
446
|
-
validate_types (bool): Whether to validate type annotations
|
|
448
|
+
text (str): Returns section contents.
|
|
447
449
|
|
|
448
450
|
Returns:
|
|
449
|
-
|
|
450
|
-
- A dictionary with 'type' and 'description' keys
|
|
451
|
-
- The string 'None' if the section only contains 'None'
|
|
452
|
-
- An empty dict if no return information is found
|
|
451
|
+
tuple[list[tuple[int, str]], tuple[int, int] | None]: Prefix tokens and zero-based separator position.
|
|
453
452
|
"""
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
)
|
|
459
|
-
|
|
453
|
+
prefix: list[tuple[int, str]] = []
|
|
454
|
+
depth = 0
|
|
455
|
+
ignored = {tokenize.NL, tokenize.NEWLINE, tokenize.INDENT, tokenize.DEDENT, tokenize.ENDMARKER, tokenize.COMMENT}
|
|
456
|
+
# An implicit group permits wrapping between any two annotation tokens, regardless of indentation.
|
|
457
|
+
tokens = tokenize.generate_tokens(io.StringIO(f"(\n{text}").readline)
|
|
458
|
+
next(tokens)
|
|
459
|
+
try:
|
|
460
|
+
for token in tokens:
|
|
461
|
+
if token.type == tokenize.NL and depth == 0 and not token.line.strip():
|
|
462
|
+
break
|
|
463
|
+
if token.type == tokenize.OP:
|
|
464
|
+
if token.string in "([{":
|
|
465
|
+
depth += 1
|
|
466
|
+
elif token.string in ")]}":
|
|
467
|
+
depth -= 1
|
|
468
|
+
elif token.string == ":" and depth == 0:
|
|
469
|
+
return prefix, (token.start[0] - 2, token.start[1])
|
|
470
|
+
if token.type not in ignored:
|
|
471
|
+
prefix.append((token.type, token.string))
|
|
472
|
+
except (tokenize.TokenError, IndentationError):
|
|
473
|
+
return prefix, None
|
|
474
|
+
return prefix, None
|
|
475
|
+
|
|
476
|
+
|
|
477
|
+
def _is_return_type(expression: ast.expr) -> bool:
|
|
478
|
+
"""Distinguish Python type expressions from wrapped numeric or prose content.
|
|
460
479
|
|
|
461
|
-
|
|
462
|
-
|
|
480
|
+
Args:
|
|
481
|
+
expression (ast.expr): Parsed candidate return annotation.
|
|
463
482
|
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
483
|
+
Returns:
|
|
484
|
+
bool: Whether the candidate has the shape of a type expression.
|
|
485
|
+
"""
|
|
486
|
+
match expression:
|
|
487
|
+
case ast.Name() | ast.Attribute() | ast.Subscript() | ast.Constant(value=str() | None):
|
|
488
|
+
return True
|
|
489
|
+
case ast.BinOp(left=left, op=ast.BitOr(), right=right):
|
|
490
|
+
return _is_return_type(left) and _is_return_type(right)
|
|
491
|
+
case _:
|
|
492
|
+
return False
|
|
467
493
|
|
|
468
|
-
# Validate type if present
|
|
469
|
-
if return_type and validate_types:
|
|
470
|
-
validate_type_annotation(return_type)
|
|
471
494
|
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
check_text_for_bare_collections(return_type)
|
|
495
|
+
def _split_return_header(text: str) -> tuple[str | None, str]:
|
|
496
|
+
"""Parse a wrapped type expression while preserving untyped prose.
|
|
475
497
|
|
|
476
|
-
|
|
498
|
+
Args:
|
|
499
|
+
text (str): Returns section contents.
|
|
500
|
+
|
|
501
|
+
Returns:
|
|
502
|
+
tuple[str | None, str]: Return annotation and its first description line.
|
|
503
|
+
"""
|
|
504
|
+
lines = text.split("\n")
|
|
505
|
+
first_line = lines[0].strip()
|
|
506
|
+
prefix, separator = _return_annotation_tokens(text)
|
|
507
|
+
if separator is None:
|
|
508
|
+
return None, first_line
|
|
509
|
+
row, column = separator
|
|
510
|
+
if row == 0:
|
|
511
|
+
annotation = first_line[:column].strip()
|
|
512
|
+
if not annotation:
|
|
513
|
+
return None, first_line
|
|
514
|
+
return annotation, first_line[column + 1 :].strip()
|
|
515
|
+
candidate = tokenize.untokenize(prefix)
|
|
516
|
+
try:
|
|
517
|
+
expression = ast.parse(candidate.strip(), mode="eval").body
|
|
518
|
+
if not _is_return_type(expression):
|
|
519
|
+
return None, first_line
|
|
520
|
+
annotation = ast.unparse(expression)
|
|
521
|
+
except (SyntaxError, ValueError, RecursionError):
|
|
522
|
+
return None, first_line
|
|
523
|
+
return annotation, lines[row][column + 1 :].strip()
|
|
477
524
|
|
|
478
525
|
|
|
479
526
|
def _process_returns_with_validation(
|
|
@@ -493,16 +540,13 @@ def _process_returns_with_validation(
|
|
|
493
540
|
if "Returns" not in sections:
|
|
494
541
|
return
|
|
495
542
|
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
result["Returns"] =
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
result["errors"].append(str(e))
|
|
504
|
-
else:
|
|
505
|
-
raise
|
|
543
|
+
return_type, return_desc = _split_return_header(sections["Returns"])
|
|
544
|
+
if return_type and validate_types:
|
|
545
|
+
_validate_type_with_error_handling(return_type, result, collect_errors)
|
|
546
|
+
if not return_type and return_desc == "None":
|
|
547
|
+
result["Returns"] = "None"
|
|
548
|
+
else:
|
|
549
|
+
result["Returns"] = {"type": return_type, "description": return_desc}
|
|
506
550
|
|
|
507
551
|
|
|
508
552
|
def _process_references_section(sections: dict[str, str], result: dict[str, Any]) -> None:
|
|
@@ -112,7 +112,7 @@ class InvalidTypeAnnotationError(ValueError):
|
|
|
112
112
|
super().__init__(message)
|
|
113
113
|
|
|
114
114
|
|
|
115
|
-
class BracketValidationError(
|
|
115
|
+
class BracketValidationError(InvalidTypeAnnotationError):
|
|
116
116
|
"""Error raised when brackets in a type annotation are not balanced or mismatched.
|
|
117
117
|
|
|
118
118
|
Contains specific error types for different bracket validation issues.
|
|
@@ -315,7 +315,7 @@ def replace_string_literals(match: Match[AnyStr], literals: list[str]) -> str:
|
|
|
315
315
|
"""
|
|
316
316
|
placeholder = str(match.group(0))
|
|
317
317
|
if placeholder.startswith("STR_LITERAL_"):
|
|
318
|
-
idx = int(placeholder.
|
|
318
|
+
idx = int(placeholder.rsplit("_", maxsplit=1)[-1])
|
|
319
319
|
if idx < len(literals):
|
|
320
320
|
return literals[idx]
|
|
321
321
|
return placeholder
|