Skip to content

Latest commit

 

History

8 Commits

Folders and files

NameName
Last commit message
Last commit date
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

@vantagecompute/docusaurus-plugin-pydoc

Docusaurus plugin that generates an SDK reference from Python docstrings.

The Python counterpart to @vantagecompute/docusaurus-plugin-godoc, with the same option shape and the same page furniture, so a reader moving between a Go spoke and a Python spoke on docs.vantagecompute.ai sees the same thing in the same places.

It parses, it does not import

Most Python autodoc tooling imports the module it documents. This does not, and that is the main design decision in the package:

  • Importing runs the module. A docs build that imports the project inherits every import-time side effect that project has, and a project that reads configuration at import time cannot be documented at all without supplying that configuration.
  • Importing needs the dependency tree installed and importable in whatever interpreter the docs build uses. Parsing needs only the source, so the plugin runs under any modern python3 rather than the project's own virtualenv.
  • An import failure is hard to attribute. A parse failure is local to one file and names that file.

The cost is that anything only knowable at runtime is invisible: attributes attached dynamically, values computed by decorators, members inherited from a base class in another module. For documenting hand-written docstrings, that trade is worth taking.

Install

yarn add -D @vantagecompute/docusaurus-plugin-pydoc

Published to npm from a tag by publish.yml, with provenance: every release is signed with the workflow and commit it was built from, so a consumer can check that the tarball came from this repository rather than from someone with a token.

A git dependency on a tag still works and needs no build step, since there is nothing to compile and no prepare script:

yarn add -D "@vantagecompute/docusaurus-plugin-pydoc@git+https://github.com/vantagecompute/docusaurus-plugin-pydoc.git#v0.1.1"

Reach for that when you need an unreleased commit. Prefer npm otherwise: it is the version with provenance attached, and a git dependency over SSH needs a key on every CI runner that installs it.

The introspector runs under python3 from PATH. It uses only the standard library.

Use

// docusaurus.config.ts
import * as path from 'path';

plugins: [
  [
    '@vantagecompute/docusaurus-plugin-pydoc',
    {
      projectRoot: path.join(__dirname, '..'),
      modules: [
        {module: 'myproject.app', label: 'app'},
        {module: 'myproject.auth', label: 'auth'},
      ],
      outputDir: './docs/sdk-reference',
      label: 'myproject',
      position: 1,
    },
  ],
],
Option Default Meaning
projectRoot required Project root, relative to the Docusaurus site directory. Both a src/ layout and a package at the root are found without configuration.
modules [] Dotted module names to document. A bare string works; {module, label} sets the display name.
outputDir ./docs/sdk-reference Where pages are written. One page per module, plus index.md.
label SDK Reference Title of the generated index page, and so the sidebar label of the category built from outputDir. Set it per instance when a site runs more than one.
position none sidebar_position for that category. Absent, sibling categories are ordered alphabetically by directory name.
python python3 Interpreter used to run the introspector. It never imports your project, so this need not be your virtualenv.
strict true Fail the build on an introspection failure. See below.

The sidebar is generated, so the front matter has to carry it

Docusaurus builds an autogenerated sidebar from the files on disk, and it reads the sidebar label and the ordering out of each page's front matter. The generator therefore emits both:

  • sidebar_label is the bare module label. title keeps its Module: prefix, because a browser tab and a search result want the longer form; a sidebar does not. Falling back to title puts a column of identical prefixes down the nav and pushes the part that distinguishes one entry from the next past the edge of a narrow sidebar.
  • sidebar_position is the module's index in the configured modules list. That list is usually ordered to read as an introduction -- settings, then auth, then the clients that use both. Without a position, Docusaurus orders alphabetically by filename and the reader gets aggregate, attachments, auth instead.

The index page carries label and position for the same reason, and it carries them for the category, not only for itself: Docusaurus consumes index.md as the category index for its directory and defaults the category's label and position to that document's. A site running one instance of this plugin per package needs that, or every one of those categories is labelled SDK Reference and the reader gets identically named siblings with no way to tell which package each holds.

No _category_.json is written. One generated page carrying its own front matter is a smaller contract with the consuming site than a second generated file it has to know about.

Failing loudly is the default

strict: true means an introspection failure fails the build, and a run in which every requested module documented zero classes and zero functions also fails the build. That second check exists because the usual cause is a wrong projectRoot or a src/ layout mismatch, not genuinely empty modules.

This is a deliberate difference from the Go sibling, which warns and continues on a per-package failure. That behaviour means a missing toolchain or a bad credential produces a green build that publishes a reference with nothing in it, and every consuming repository has to add its own verification step to notice. Failing the build is the behaviour that needs no workaround downstream.

Set strict: false if you want warn-and-continue anyway.

What appears in the output

Per module: the module docstring as an Overview, public upper-case module constants, public classes with their bases, decorators, annotated attributes and public methods, and public module-level functions. Signatures are rendered from source, so annotations, defaults, positional-only and keyword-only markers, *args and **kwargs all survive.

A name starting with an underscore is private and skipped, except for the dunders worth documenting when they carry a docstring: __init__, __call__, and the sync and async context-manager pairs.

Docstrings are emitted verbatim. They are prose written by the same people who wrote the code, and reflowing them here would mangle the indented blocks, tables and reStructuredText roles many of them contain.

Standalone use

Without a Docusaurus build:

node node_modules/@vantagecompute/docusaurus-plugin-pydoc/src/generate.js \
  --project-root .. \
  --output-dir ./docs/sdk-reference \
  --modules myproject.app,myproject.auth \
  --label myproject --position 1

Or the introspector alone, which prints JSON and is the thing to reach for when the rendered output looks wrong and you want to see what was actually extracted:

python3 node_modules/@vantagecompute/docusaurus-plugin-pydoc/src/introspect.py \
  --root .. --module myproject.app

Releasing

just release 0.1.1 bumps, tags, pushes and creates the GitHub release. Publishing that release to npm is publish.yml, which runs on release: published and can also be fired by hand against a tag.

It publishes with --provenance, which needs id-token: write on the job and a release built by Actions rather than from a laptop. That is the reason to keep publishing here rather than running npm publish locally: a local publish is unattested, and once one version in a package is unattested the guarantee is only as good as the weakest release.

License

MIT

About

Docusaurus plugin that auto-generates SDK reference docs from Python docstrings, by parsing source rather than importing it

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages