AlgoMaster Logo

Documentation

Low Priority29 min readUpdated September 21, 2026
Listen to this chapter
Unlock Audio

Code answers the question "what does this do." Documentation answers everything else: why does this project exist, how do I install it, what does a typical usage look like, what guarantees does the API make, and where do I report bugs. This lesson covers the kinds of documentation a Python project needs, the tools that generate them, and how to keep the docs honest as the code changes.

Types of Documentation

A single Python project usually has four kinds of documentation, each with a different audience and purpose. Confusing one for another is a common mistake.

TypeAudienceQuestion it answersWhere it lives
READMEFirst-time visitorWhat is this, why would I use it, how do I install it?Root of the repository
DocstringsDeveloper reading the codeWhat does this function do, what are its arguments?Inside the source files
Tutorials and guidesNew user learning the projectHow do I accomplish task X step by step?A docs/ folder, hosted online
API referenceExisting user looking up a detailWhat's the exact signature of cart.add_item?Auto-generated from docstrings

Each one builds on the others. The README is the front door. Docstrings are the source of truth that everything else derives from. Tutorials show real workflows. The API reference catalogs every public function and class.

The arrows match the order a typical user walks through the docs. They land on the README, follow a tutorial to get something running, consult how-to guides when they hit a specific task, and dip into the API reference when they need precise details. The docstrings inside your source files feed the API reference automatically, so the same prose appears in two places: in the source for developers, and on the docs site for users.

The README

The README is the first thing anyone sees on GitHub, PyPI, or your project's homepage. If it's bad, visitors often leave. If it's good, it tells them in 30 seconds whether the project is worth their time and how to get started.

A solid README has roughly this shape:

  1. Project name and one-line description. What this is, in a single sentence.
  2. Badges (optional). Build status, version, license, coverage. Use sparingly.
  3. Why this exists. The problem it solves, in two or three sentences.
  4. Installation. The exact command, copy-pasteable.
  5. Quick start. A 10 to 20 line example that does something real.
  6. Links to longer docs. Tutorials, API reference, contributing guide.
  7. License and contributing info. A line each, with a link.

A minimal example for a fictional shopping cart library:

The structure is deliberate. The first paragraph answers "what is this." The "Why" section answers "should I care." Install and Quick Start let the reader run something within a minute. Everything else is a link, not a wall of text.

What to leave out of the README: the entire API reference, long architecture discussions, every configuration option. Those belong in dedicated docs. The README is for the first impression, not completeness.

Project Documentation: Tutorials, Guides, and API Reference

When a project grows past a single README, you need a docs site. There's a well-known model for organizing it, called the Diataxis framework, that splits docs into four categories based on what the reader is trying to do.

CategoryReader's goalExample title
TutorialLearn by doing"Build your first shopping cart with cartkit"
How-to guideSolve a specific problem"How to apply percentage discounts to a cart"
ReferenceLook up a fact"Cart.add_item(name, price, quantity=1)"
ExplanationUnderstand the why"How cartkit handles tax rounding"

Most small projects don't need all four. A useful starting point is a README, a single tutorial, and an auto-generated API reference. As the project grows, you add how-to guides for the questions users keep asking, and you add explanations for the design decisions that need context.

A common mistake is mixing categories in the same page. A tutorial that veers into how-to material loses its narrative. An API reference that includes a long explanation forces the reader to scroll past prose to find a method signature. Pick one category per page.

The Quick-Start Tutorial

A quick-start tutorial walks a new user through a complete, end-to-end example in 15 to 30 minutes. It assumes nothing except "you have Python installed." It builds up to one finished piece of working code by the end.

A pattern that works:

  1. Set the goal. State the deliverable in one sentence ("a working shopping cart that computes totals with tax and discount").
  2. Install. One command. Don't make them debug their environment.
  3. First runnable snippet. Eight to ten lines. Print something.
  4. One concept at a time. Each step adds one new idea. Don't introduce three at once.
  5. Show the output after every step. The reader should see the same output you describe.
  6. End with the complete program. Everything they built, in one block they can copy.

The tutorial is the project's onboarding. If a new user can't follow it without getting stuck, they often leave. Teams that care about adoption put more effort into the tutorial than into anything else, because it's the page that converts visitors into users.

How-To Guides

A how-to guide answers a specific question. "How do I apply a discount that only kicks in above a minimum order value?" "How do I export a cart to JSON?" Each guide is short (a screenful or two), focused on one task, and assumes the reader already knows the basics.

How-to guides accumulate over time. You write them when users ask the same question more than twice. A useful pattern:

  1. State the problem in the title.
  2. Give the shortest solution that works.
  3. Explain the parts that aren't obvious.
  4. Link to deeper material if the reader wants more.

What a how-to is not: a tutorial. Tutorials teach concepts in order. How-tos assume the concepts and skip to the solution.

The API Reference

The API reference is the long, exhaustive list of every public function, class, and method, with their signatures and descriptions. It's the page users go to when they know what they want and need a detail.

You don't write the API reference by hand. You write docstrings inside your source code, and a tool generates the reference from them.

Documentation Tools

Three tools cover almost every Python project: Sphinx, MkDocs, and pdoc. Each has a different philosophy.

Sphinx

Sphinx is the original Python documentation generator, written in Python itself and used by the standard library, NumPy, Django, and most of the older big projects. It was built around reStructuredText (ReST), a markup language that's more powerful than Markdown but less familiar.

After running the quick-start, you have a docs/ directory with a conf.py, an index.rst, and a Makefile. You write pages in .rst files, run make html, and Sphinx builds a static HTML site.

Sphinx's strengths:

  • Cross-references. You can link to any function, class, or section by name, and Sphinx checks that the link target exists.
  • Extensions. A large ecosystem of plugins for diagrams, math, automatic API generation, multi-language support.
  • Auto-generated API docs. The autodoc extension reads your source code, finds the docstrings, and turns them into reference pages.
  • Multi-format output. HTML, PDF, ePub, man pages.

Sphinx's weaknesses:

  • ReST is harder to learn than Markdown. The syntax for links, code blocks, and cross-references is its own thing.
  • The default theme is dated. Most projects use furo or sphinx-rtd-theme instead.
  • The configuration is verbose. conf.py has dozens of settings and the docs are dense.

Sphinx is the right pick when you need its capabilities: cross-references that survive refactors, math rendering, multi-version docs, or PDF output for a book-style project. It's overkill for a small library with one tutorial and an API reference.

MkDocs

MkDocs is younger and Markdown-based. You write pages in Markdown, configure a single YAML file, and run mkdocs serve to preview locally. The output is a clean static site.

The default theme is plain, but the Material theme (from mkdocs-material) gives you a clean, modern look out of the box. Most new Python projects in the last few years that picked MkDocs picked it with Material.

MkDocs's strengths:

  • Markdown. Widely known, low learning curve.
  • Fast preview. mkdocs serve watches files and reloads in milliseconds.
  • Simple config. One YAML file with a clear structure.
  • Modern themes. Material is among the most readable.

MkDocs's weaknesses:

  • Weaker cross-references. Linking to a function by name across pages takes plugin help.
  • API generation needs a plugin. mkdocstrings does the job, but it's a separate install.

A rough decision rule: pick MkDocs (with Material) for new small-to-medium projects that prioritize ease of writing. Pick Sphinx when the docs need to grow into something more involved.

pdoc

pdoc is the simplest option. It takes a Python module, reads its docstrings, and generates an HTML API reference. That's it. No tutorials, no how-to guides, only the reference pages.

For a small library where the README is the tutorial and the API reference is all the user docs you need, pdoc is the fastest path from "I have docstrings" to "I have a docs site." It's a poor fit for a project with extensive tutorials or how-to material.

Comparison

ToolFormatBest forDefault themeAPI generation
SphinxreStructuredText (Markdown via plugin)Large projects, multi-format outputalabaster (most use furo or rtd)Built-in (autodoc)
MkDocsMarkdownSmall to medium projects, modern lookPlain (Material recommended)Plugin (mkdocstrings)
pdoc(none, reads docstrings)API reference only, tiny projectsMinimal HTMLBuilt-in

For a fresh project today, the common starting point is MkDocs with the Material theme and the mkdocstrings plugin. It gives you Markdown for prose, auto-generated API reference from docstrings, and a clean output, all in about 50 lines of YAML config.

ReST vs Markdown

The format question matters because it affects who can contribute to your docs and how much friction that contribution carries. Most non-Python developers know Markdown. ReST is mostly known to people who already work on Python projects.

A side-by-side of the same content:

Markdown:

reStructuredText:

Both produce the same visible result. The ReST version uses roles (:class:, :meth:, :doc:) that Sphinx understands. The roles let Sphinx check that the linked target exists, jump straight to it, and update the link automatically if the target moves. Markdown doesn't have that out of the box; you can get most of it back with plugins, but the default is a plain link.

The trade-off is reach versus capability. Markdown is universal, easy to teach, and good enough for almost everything. ReST is more capable when the docs site gets large, but the entry cost is higher.

MyST is a Markdown extension that adds ReST's features back. Sphinx supports it as a first-class input format, so a modern Sphinx project can use Markdown for prose and ReST roles for the cross-references. That setup gives you both, at the cost of two formats living in the same repo.

Hosting Documentation

Once you've built the site locally, you need somewhere to host it.

Read the Docs is the standard Python doc host. It's free for open-source projects, automatically rebuilds the docs on every push to your git repo, supports multi-version docs (one URL per release), and works with Sphinx and MkDocs. Most well-known Python libraries host their docs there: Django, Flask, requests, pytest, hundreds more.

The setup is a config file in your repo:

Push, and Read the Docs builds your site. Future pushes trigger automatic rebuilds. The free plan covers public projects with reasonable limits; the paid plan supports private repos and larger build minutes.

GitHub Pages is the simpler alternative. You publish a built HTML directory to a gh-pages branch (or a docs/ folder on main), and GitHub serves it. MkDocs has a built-in command for this:

The command builds the site, commits the output to gh-pages, and pushes. GitHub serves the result at https://yourname.github.io/project-name/. No external service needed.

Other hosts. Cloudflare Pages, Netlify, and Vercel all support static sites. For a docs site, any of them works the same way: build the HTML locally or in CI, push it to the host, and the host serves it. They're useful when you want a custom domain or when GitHub Pages and Read the Docs don't fit.

A common pattern for established projects: Read the Docs hosts the long-form docs (tutorials, guides, reference), GitHub Pages hosts the project's homepage (a single landing page), and the README on GitHub does the rest. Together they cover every audience.

What to Document

A practical checklist of what a Python project should document. Not every project needs all of these. Start small and add as users ask questions.

  • Purpose. One paragraph at the top of the README that explains why the project exists.
  • Install. The exact command and any prerequisites.
  • Quick start. Ten to twenty lines of code that produces visible output.
  • Tutorial. A 15 to 30 minute walkthrough of building something real.
  • API reference. Auto-generated from docstrings. Every public function and class.
  • How-to guides. One per common task. Grows over time.
  • Configuration. Every option, with defaults and examples.
  • Changelog. A CHANGELOG.md listing what changed in each release.
  • Contributing. A CONTRIBUTING.md explaining how to set up the dev environment, run tests, and submit changes.
  • License. A LICENSE file at the repo root. Choose one of the standard open-source licenses (MIT, Apache 2.0, BSD) unless you have a specific reason not to.

What you don't need to document: every internal helper function, every private method, every detail of the implementation. Internal code is documented by the source itself. Documentation effort should go to the public surface.

The flow matches how documentation gets used in practice. A user starts at the README, runs the tutorial, builds something, and then dips into how-to guides or the API reference when they hit specific questions. Each layer of documentation handles one stage. Skip a layer and the user can get stuck.

Versioning Documentation

When a project has multiple releases, the docs need to track which version they describe. A function that exists in 2.0 might not exist in 1.5, and a user on the old version needs the old docs.

Read the Docs handles this automatically. Each git tag becomes a documentation version, and the site shows a version picker so users can switch between them. The URL pattern is cartkit.readthedocs.io/en/v1.5/ for version 1.5, cartkit.readthedocs.io/en/latest/ for the current main branch.

Inside the docs, mark version-specific information explicitly. Sphinx has .. versionadded:: and .. versionchanged:: directives:

Markdown projects do the same thing manually:

Either form gives the reader context without forcing them to dig through a changelog.

Living Documentation

Documentation rots when it's separated from the code. You change a function signature, you forget to update the docstring, and three months later a user files a bug because the docs are wrong.

Practices that keep docs honest:

  • Docstrings live in the source code, so a code change and a doc change happen in the same commit.
  • API reference is auto-generated, so the signatures in the docs are always the actual signatures.
  • Code examples in docs are tested. Sphinx's doctest extension and MkDocs's pytest-markdown-docs plugin both run the example code and fail the build if it doesn't produce the documented output.
  • Type hints catch drift. If a docstring claims a function returns a Cart but the signature says Order, the type checker flags the mismatch before users do.

A useful rule: if the docs and the code disagree, the code is the source of truth. The fix is to update the docs, not the code. The auto-generation patterns above make this rule easier to follow, because much of the doc content comes straight from the source.

Type Hints as Documentation

Python 3 brought type hints, and they changed what you have to write down. Before type hints, a function signature like def add(name, price, quantity=1): told you nothing about what types were expected. The docstring had to say "name is a string, price is a float, quantity is an int." After type hints:

The signature itself tells you that name is a str, price is a float, quantity is an int (with a default of 1), and the function returns None. The docstring no longer needs to repeat that information; it can focus on what the function does and any non-obvious behavior.

Modern Python documentation is shorter than it used to be because of this. Type information lives in the signature, where it's checked by tools like mypy and pyright. The docstring covers what's left: the purpose, edge cases, raised exceptions, and usage notes.

A practical comparison. Before type hints, a docstring might look like:

With type hints, the same function:

The types moved into the signature, so the docstring describes only the non-obvious behavior (the decimal-not-percentage convention). The docstring got shorter, the signature got more informative, and the type checker can now catch a mistake at the call site if someone passes 10 instead of 0.10.

When Docs Aren't Needed

Not every Python file needs documentation. The cases where less is more:

  • Private internal scripts. A one-off script you'll throw away next week doesn't need a README. Add comments where the logic is non-obvious; skip the rest.
  • Throwaway experiments. Jupyter notebooks for exploration, scratch files, prototypes. Don't spend time documenting code you're about to delete.
  • Tightly scoped internal tooling. A 50-line script that converts CSVs for one specific report doesn't need a tutorial. A README with three lines is enough.
  • Implementation details of a library. The public API gets full documentation. The private helper functions inside it get docstrings only when they're non-obvious.

The rule is to document the parts other people interact with. If a file or function is only called by code in the same repo, a docstring is enough. If something is called by other developers, other teams, or external users, it needs proper docs.

Over-documenting has a real cost. Every paragraph you write is something that has to be maintained, and an out-of-date paragraph is worse than no paragraph. Aim for the minimum that lets your users succeed, then add more when they ask for it.

Why wishlist

Most e-commerce sites need a wishlist feature, but rolling it from scratch means writing the same code for adding items, removing items, and checking duplicates. wishlist gives you those primitives without any database dependency, so you can store wishlists in memory, in JSON files, or wire it to your own storage layer.

Install

pip install wishlist

Quick start

from wishlist import Wishlist

wishlist = Wishlist(customer_email="aanya@example.com") wishlist.add("headphones", price=59.99) wishlist.add("laptop stand", price=29.99)

print(wishlist.items) print(f"Total if bought: ${wishlist.total():.2f}")

Learn more

  • Full docs: https://wishlist.readthedocs.io
  • Source: https://github.com/example/wishlist
  • License: MIT

site_name sets the title shown in the browser tab and header. theme.name: material activates the Material theme. nav is the ordered list of pages in the sidebar. Each entry maps a display name to a Markdown file in the docs/ directory.

</details>

Exercise 3: Classify each of these doc pages as a tutorial, how-to guide, reference, or explanation.

  1. "Build your first shopping cart in 20 minutes"
  2. "Why we chose Decimal over float for prices"
  3. "How to apply a discount that only kicks in above a minimum order"
  4. "Cart.add_item(name, price, quantity=1) documentation"

<details> <summary>Solution</summary>

  1. Tutorial. The title promises a step-by-step walkthrough with a finished result.
  2. Explanation. It's about understanding a design decision, not doing something.
  3. How-to guide. A specific question with a specific solution.
  4. Reference. A signature and parameter description, looked up when the reader needs a precise detail.

Pages that mix categories tend to fail at least one audience. A tutorial that veers into the float-vs-Decimal trade-off loses momentum; a how-to that includes a 20-minute walkthrough wastes the experienced reader's time.

</details>

Exercise 4: A function signature changes from def add(name, price) to def add(name, price, quantity=1). List two ways to make sure the docs reflect the change.

<details> <summary>Solution</summary>

Option 1: Auto-generated API reference. If the project uses Sphinx's autodoc or MkDocs's mkdocstrings, the reference page rebuilds on every doc build and pulls the new signature from the source automatically. No manual update needed for the signature itself.

Option 2: Doc tests. If the docs include example code (in a tutorial or how-to guide), tools like Sphinx's doctest extension or MkDocs's pytest-markdown-docs plugin run the examples as part of the build. If the old example used add("headphones", 59.99) and the new signature now expects three arguments, the example fails the build and you catch it before users do.

Both should be set up together. Auto-generation keeps the reference correct; doc tests catch broken examples in the prose.

</details>

Exercise 5: Write a .readthedocs.yaml that builds a Sphinx-based docs site using Python 3.11 and installs the doc requirements from docs/requirements.txt.

<details> <summary>Solution</summary>

build chooses the OS and Python version Read the Docs uses. sphinx.configuration points at the conf.py. python.install lists what to install before building the docs; docs/requirements.txt typically pins Sphinx, the theme, and any extensions.

</details>

Exercise 6: Identify three problems with this README excerpt and suggest fixes.

<details> <summary>Solution</summary>

Three problems:

  1. No description of what the project does. "My Python library" tells the reader nothing. Fix: replace the first line under the title with a concrete one-liner ("A small library for managing customer wishlists in Python") and a paragraph on why it exists.
  2. No install command. "Email me for installation help" is friction. Fix: add a pip install my-project block.
  3. No quick-start example. "Read all the docs" is a wall; a 10-line example shows the value in seconds. Fix: add a Quick Start section with a small runnable snippet that produces visible output.

A revised version uses the standard pattern: title, one-line summary, why, install, quick start, links.

</details>

Exercise 7: A project has these four docstring conventions across its files. Which one is most useful for users in 2024?

<details> <summary>Solution</summary>

The second one. Type hints (name: str, price: float, -> None) carry the type information that the first version puts in @param tags. The docstring is short because the signature already says everything the user needs to know about types, so it can focus on the human-readable purpose. The first version duplicates information; the third leaves out the types; the fourth uses a comment where a docstring should be (a # comment doesn't show up in help() or in auto-generated docs).

The modern pattern: type hints in the signature, prose in the docstring, no overlap between them.

</details>

Exercise 8: A teammate proposes putting the full API reference inside the README so users don't have to leave GitHub. What's the problem with this, and what's the alternative?

<details> <summary>Solution</summary>

The problem: the API reference for a non-trivial library can be thousands of lines, and the README is meant to be scanned in 30 seconds. Putting the reference in the README pushes the install instructions and quick-start example below the fold, so visitors leave without trying the project. It also means every signature change requires a manual README update.

The alternative: keep the README focused on the first impression (what, why, install, quick start, links) and put the API reference on the docs site, auto-generated from docstrings. GitHub doesn't render an auto-generated reference inline, so the natural home is a separate docs site (Read the Docs, GitHub Pages, etc.) linked from the README.

</details>

Exercise 9: A small internal script that one person on the team uses occasionally has no README and no docstrings. The script is 80 lines. Is this a problem?

<details> <summary>Solution</summary>

Probably not. A small internal script used by one person doesn't need formal documentation. The author can read the code; nobody else is going to call it. Adding a README and docstrings for the sake of "documenting everything" is busy work that produces material no one will read.

What's worth adding even for a small script:

  1. A short comment at the top explaining what the script does and how to run it (one or two lines).
  2. Comments inside the script where the logic is non-obvious.

The full documentation pattern (tutorial, reference, etc.) only pays off when there are users beyond the author. The judgment call is whether a second person would ever need to understand this. If yes, document it. If no, comments are enough.

</details>

Exercise 10: Your library is at version 2.0. A function cart.set_discount(percent) existed in 1.x and was removed. A user on 1.5 reads the latest docs and is confused that set_discount is gone. What docs practices would prevent this?

<details> <summary>Solution</summary>

Two practices, both common in well-maintained Python projects:

1. Versioned documentation. Read the Docs builds a separate docs site per git tag and shows a version picker. A user on 1.5 can switch to the 1.5 docs and see set_discount documented as it existed. The 2.0 docs don't show it because it's gone. The user picks their version and gets the matching docs.

2. Deprecation notes in the docs. Before removing set_discount in 2.0, the 1.x docs should have marked it as deprecated with a pointer to the replacement:

A 2.0 changelog entry that says "Removed set_discount, use apply_discount" gives users a migration path. Combining the two helps: versioned docs let old users find their version, and deprecation notes warn current users before the breaking change lands.

</details>

Quiz

Documentation Quiz

10 quizzes