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+Don 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/Returnssections) - reStructuredText / Sphinx (
:param:/:type:/:return:/:rtype:/:raises:)
- Google (
- Deep static parsing — no external AST library, no shelling out to Python. Handles:
- Functions, methods,
async deffunctions, and nested (closure) functions - Classes and
__init__constructors, withself/clsautomatically excluded from the parameter list @staticmethod,@classmethod, and@propertydecorators- Positional-only (
def f(a, b, /)), keyword-only (def f(*, x)),*args, and**kwargsparameters — correctly classified even when mixed in one signature - Type hints, including
Optional[X],Union[X, Y], PEP 604X | None,Literal[...],List,Tuple,Dict,Set,FrozenSet, and arbitrary generic/custom types dataclasses,NamedTuple,TypedDict,Enum/IntEnum/Flag,Protocol, andABC/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 ...")raisestatements, 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.)
- Functions, methods,
- 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/byou'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/classline is located, then its parameter list (or base-class list, for a class) is extracted using bracket-depth-aware scanning that treats(),[], and{}uniformly — soDict[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
publisherinpackage.jsonto 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
.vsixlocally before publishing:code --install-extension python-docstring-auto-generator-1.0.0.vsix - Log in and publish:
Alternatively, upload thevsce login <your-publisher-id> npm run publish # runs `vsce publish`.vsixmanually via the "Manage Publisher" page on the Marketplace. - Bump
versioninpackage.json(and add an entry toCHANGELOG.md) before every subsequent publish —vsce publish patch|minor|majorwill 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.