Python Docstring Auto Generator
Generate professional Python docstrings — Google, NumPy, or reStructuredText/Sphinx
style — for functions, methods, classes, and constructors with a single keystroke, entirely
offline. No OpenAI, no Gemini, no Claude, no Llama, no cloud service, no backend, no database,
no Python runtime, no internet access of any kind. Everything runs locally inside VS Code using
static code analysis written in TypeScript.

Features
- One shortcut, zero setup. Place your cursor inside or above any function, method, class, or
constructor and press
Ctrl+Shift+Alt+D (Cmd+Shift+Alt+D on macOS) — or run Python
Docstring Auto Generator: Generate Docstring from the Command Palette.
- Batch mode. Run Python Docstring Auto Generator: Generate Docstrings for All Definitions
in File to document an entire module in one pass.
- Three interchangeable styles, switchable in settings at any time:
- Google (
Args: / Returns: / Raises: / Yields:)
- NumPy (underlined
Parameters / Returns sections)
- reStructuredText / Sphinx (
:param: / :type: / :return: / :rtype: / :raises:)
- Deep static parsing — no external AST library, no shelling out to Python. Handles:
- Functions, methods,
async def functions, and nested (closure) functions
- Classes and
__init__ constructors, with self/cls automatically excluded from the
parameter list
@staticmethod, @classmethod, and @property decorators
- Positional-only (
def f(a, b, /)), keyword-only (def f(*, x)), *args, and **kwargs
parameters — correctly classified even when mixed in one signature
- Type hints, including
Optional[X], Union[X, Y], PEP 604 X | None, Literal[...],
List, Tuple, Dict, Set, FrozenSet, and arbitrary generic/custom types
dataclasses, NamedTuple, TypedDict, Enum / IntEnum / Flag, Protocol, and
ABC/ABCMeta-based classes — each gets a tailored one-line class summary
- Generators (
yield / yield from), producing a Yields section instead of Returns
@contextmanager-decorated functions ("Context manager that ...")
raise statements, producing an accurate Raises section with specific phrasing for common
built-ins (ValueError, KeyError, FileNotFoundError, RuntimeError, ...)
- Overloaded-looking same-named functions (each documented independently, matching its own
parameters)
- Multi-line signatures with wrapped parameter lists
- One-line inline bodies (
def f(): return 1), safely split into a proper multi-line body with
the docstring inserted correctly
- Lambda assignments (
handler = lambda event: ...) — documented with a short # comment above
the assignment, since a lambda's single expression cannot contain a docstring statement
- Dunder methods (
__repr__, __eq__, __len__, __enter__, __exit__, etc.)
- Intelligent descriptions. Function names are decomposed (
get_user → "Returns the user.",
calculate_salary → "Calculates the salary.", is_enabled → "Checks whether enabled.") and
parameter names are matched against a built-in dictionary (id → "Unique identifier.", path
→ "File path.", config → "Configuration object.", …).
- Type-aware Returns/Yields text for booleans,
str, int, float, collections, Optional,
Iterator, Generator, and custom objects.
- Never duplicates a docstring. If a definition already has one (single-line or multi-line),
it's left untouched unless you opt in to
overwriteExisting.
- Preserves indentation, matching the file's existing indent unit (spaces or tabs) even when
a function body is currently empty.
Examples
Input:
def add_numbers(a: int, b: int) -> int:
return a + b
Google style (Ctrl+Shift+Alt+D):
def add_numbers(a: int, b: int) -> int:
"""Adds the numbers.
Args:
a (int): The a parameter.
b (int): The b parameter.
Returns:
int: Computed integer.
"""
return a + b
NumPy style:
def add_numbers(a: int, b: int) -> int:
"""Adds the numbers.
Parameters
----------
a : int
The a parameter.
b : int
The b parameter.
Returns
-------
int
Computed integer.
"""
return a + b
Sphinx style:
def add_numbers(a: int, b: int) -> int:
"""Adds the numbers.
:param a: The a parameter.
:type a: int
:param b: The b parameter.
:type b: int
:return: Computed integer.
:rtype: int
"""
return a + b
For well-named signatures the results read naturally out of the box:
def find_employees(department: str, active_only: bool) -> List["Employee"]:
becomes (Google style):
"""Finds the employees.
Args:
department (str): Department.
active_only (bool): Flag indicating whether active only.
Returns:
List[Employee]: List containing employees.
"""
Static analysis can't read your mind — for terse parameter names like a/b you'll still want
to tighten the wording by hand. The generator gives you a correct, complete scaffold every time
so you never start from a blank docstring.
Extension Settings
| Setting |
Default |
Description |
pythonDocstringAutoGenerator.style |
google |
Docstring style: google, numpy, or sphinx. |
pythonDocstringAutoGenerator.enableReturnSection |
true |
Include a Returns/Yields section when applicable. |
pythonDocstringAutoGenerator.enableRaisesSection |
true |
Include a Raises section for exceptions found in the body. |
pythonDocstringAutoGenerator.enableExamples |
false |
Include a placeholder Examples section. |
pythonDocstringAutoGenerator.blankLineAfterSummary |
true |
Insert a blank line after the summary sentence. |
pythonDocstringAutoGenerator.quoteStyle |
double |
double (""") or single (''') triple quotes. |
pythonDocstringAutoGenerator.overwriteExisting |
false |
Replace an existing docstring instead of skipping the definition. |
pythonDocstringAutoGenerator.maxLineWidth |
88 |
Maximum line length before description text wraps. |
The keybinding (Ctrl+Shift+Alt+D / Cmd+Shift+Alt+D) can be changed from File → Preferences →
Keyboard Shortcuts by searching for "Python Docstring Auto Generator".
Requirements
None. The extension has zero runtime dependencies (beyond the VS Code API itself) and makes zero
network requests. It only needs a .py file open in the editor — no Python interpreter required.
How it works (architecture)
src/
model/
PythonMember.ts Shared data model for a parsed function/method/class/lambda
parser/
PythonMemberParser.ts Framework-agnostic static analyzer: finds the definition under/near
the cursor using indentation-based scanning and extracts
decorators, parameters, type hints, return type, yield/raise
usage, and enclosing-class scope
generator/
BaseDocstringGenerator.ts Shared content assembly: summary, params, returns/yields, raises,
examples — identical logic reused by every style
DocstringContent.ts Style-neutral intermediate representation
DocstringGeneratorFactory.ts Picks the concrete style implementation
LambdaCommentGenerator.ts Single-line "#" comment generator for lambda assignments
DescriptionDictionary.ts Word/phrase dictionaries for name and exception-type inference
PythonTypeUtils.ts Type-hint parsing and Returns/Yields phrasing (generics, Optional,
Union, collections, ...)
styles/
GoogleStyleGenerator.ts Args:/Returns:/Raises:/Yields:
NumpyStyleGenerator.ts Underlined Parameters/Returns/Raises/Yields sections
SphinxStyleGenerator.ts :param:/:type:/:return:/:rtype:/:raises:
utilities/
StringUtils.ts snake_case splitting, text wrapping, sentence helpers
PythonTextUtils.ts Bracket/paren/brace/string/comment-aware text scanning
IndentUtils.ts Indentation-unit detection and Python block-body boundaries
extension.ts VS Code entry point: commands, keybindings, editor integration
test/
parser.test.ts Unit tests for every supported parsing construct
generator.test.ts Unit tests for all three styles and content inference
The parser and generators have no dependency on the vscode module, so the entire analysis
and generation pipeline is unit-tested with plain Mocha (npm test) without needing to launch the
VS Code Extension Host.
Parsing strategy
Python has no braces, so the parser can't reuse a brace-matching approach — it works with
indentation instead:
- Comments and string-literal contents are replaced with spaces, character-for-character (not
removed), so every index found while scanning the "masked" text is still a valid index into the
original source — no separate offset bookkeeping is needed.
- Every
def / async def / class line is located, then its parameter list (or base-class
list, for a class) is extracted using bracket-depth-aware scanning that treats (), [], and
{} uniformly — so Dict[str, List[int]] and multi-line wrapped signatures are handled
without special-casing.
- Decorators are collected by walking upward from the signature for contiguous
@-prefixed
lines.
- Each definition's enclosing class (if any) and nesting status are computed with a single
indentation-based scope stack pass across the whole file, so a method inside a nested class is
correctly distinguished from a function nested inside a function.
- A definition's body boundary — and therefore whether the cursor sits "inside" it — is found by
scanning forward for the first line whose indentation is not greater than the signature's own,
skipping blank lines.
- Resolving which candidate belongs to the cursor mirrors the JavaDoc-generator design: inside a
body → that definition (innermost first); on or above a signature (including on a blank line,
a comment, or a decorator line) → the next definition reachable without crossing unrelated
code.
Development
npm install
npm run compile # one-off TypeScript build
npm run watch # incremental build
npm run lint # ESLint
npm test # compiles then runs the Mocha unit test suite
Press F5 in VS Code (with this folder open) to launch an Extension Development Host with the
extension loaded — open any .py file and try Ctrl+Shift+Alt+D.
Packaging & publishing to the Visual Studio Marketplace
- Update
publisher in package.json to your Marketplace publisher ID (create one for free at
https://marketplace.visualstudio.com/manage if you don't have one, using a Personal Access
Token from https://dev.azure.com).
- Install the packaging CLI (one time):
npm install -g @vscode/vsce
- Build and package:
npm run compile
npm run package # runs `vsce package`, producing python-docstring-auto-generator-1.0.0.vsix
- Test the packaged
.vsix locally before publishing:
code --install-extension python-docstring-auto-generator-1.0.0.vsix
- Log in and publish:
vsce login <your-publisher-id>
npm run publish # runs `vsce publish`
Alternatively, upload the .vsix manually via the "Manage Publisher" page on the Marketplace.
- Bump
version in package.json (and add an entry to CHANGELOG.md) before every subsequent
publish — vsce publish patch|minor|major will bump and publish in one step.
Known limitations
- Terse or single-letter parameter/function names (
a, b, f) produce a generic placeholder
description rather than true semantic meaning — no static analyzer can infer intent that isn't
present in the code. Descriptive identifiers get the best results.
- Multi-line decorator calls (a decorator whose own argument list wraps across several lines) are
not specially parsed; only the immediate
@... line directly above the signature is collected.
Single-line decorators (the overwhelming majority in real code) work fully.
- Multi-statement inline bodies separated by
; (e.g. def f(): x = 1; return x) are detected as
having an inline body, but only the leading statement is inspected when deciding whether a
Returns section is needed.
- Sphinx/reST has no universally standardized "yields" field, so generator functions in that style
reuse
:return:/:rtype:, consistent with common Sphinx/Napoleon usage.
License
MIT — see LICENSE.
| |