Skip to main content

PyPI version License: Apache 2.0 Framework: Sphinx

markwork v0.1.0 (alpha)

markwork publishes your source as your documentation. The page for a file is that file: rendered verbatim, syntax-highlighted, and with every name turned into a link to wherever it is defined. It replaces autodoc, not Sphinx.

Stop documenting your code. Start publishing it.

Table of Contents

Installation

Install with pip:

pip install markwork

This pulls in Sphinx and Pygments. markwork rides on Sphinx for the HTML shell, search, theme, and hosting. What it replaces is autodoc.

You Already Wrote the Docs

Here is a function. It is documented. You have written a hundred like it:

def fib(n: int) -> int:
  """Return the nth Fibonacci number.

  Parameters
  ----------
  n : int
      Position in the sequence, counting from zero.

  Returns
  -------
  int
      The nth Fibonacci number.

  Examples
  --------
  >>> fib(10)
  55
  """
  a, b = 0, 1
  for _ in range(n):
    a, b = b, a + b
  return a


class IsEven(metaclass=type('_', (), {'__call__': lambda *a: not a[1] % 2})):
  """
  Parity test of integers. 

  Parameters
  ----------
  n : int
      The integer to test.

  Returns
  -------
  bool
      True if 'n' is even, False otherwise.

  Examples
  --------
  >>> IsEven(4)
  True
  >>> IsEven(7)
  False
  """

Then the ceremony starts. A .rst stub. An automodule directive. A docstring style your theme half-renders. A [source] link that ejects the reader into a separate viewer to see the four lines that actually matter.

Wouldn't it be easier if you wrote that docstring and were just done?

Now you are. Add one line to conf.py:

extensions = ["markwork"]

markwork publishes the function — docstring, signature, body, all of it — exactly as you wrote it. The page is the source. You already finished the documentation; you just did not know it yet.

Click a Name, Land on the Definition

markwork reads your syntax tree, so every name on the page is wired to where it comes from. You do not read the docs by scrolling. You read them the way you read code — by following definitions:

widget.py     click Point  →  geometry.py:14   (the def, highlighted)
geometry.py   click hypot  →  docs.python.org/3/library/math.html
sequences.py  click fib    →  sequences.py:30  (back to its own def)

Project symbols and same-file names jump inside your docs, at the exact line. Standard-library members and builtins jump to the official Python documentation. A name shadowed by a local binding stays unlinked, so a link never sends you somewhere wrong.

Every Page Ends With Its Tests

Scroll to the bottom of any symbol's page and the tests that exercise it are waiting there — listed for you, no digging, file and line, each line a link straight to the assertion:

fib()

Usage in testing
────────────────
  tests/test_sequences.py:  12,  19,  27

Click 19 and you land on that line of the test. Per function, you can see exactly what is covering it. You did write tests, right?

Quickstart

A complete src/-layout project, zero to rendered docs in about a minute.

acme/
├─ src/acme/__init__.py     # re-exports your public names, sets __all__
├─ src/acme/widget.py
├─ tests/test_widget.py
└─ docs/
   ├─ conf.py               # extensions = ["markwork"]
   └─ index.rst

markwork follows your public API: every name in the package's __all__ becomes a page, a re-exported symbol pulls in its defining file, and the tests/ tree is mirrored for you. So the package's __init__.py is your table of contents:

# src/acme/__init__.py
from .widget import Widget

__all__ = ["Widget"]

docs/index.rst needs a single include — markwork writes the tree into _source/:

acme
====

.. include:: _source/_packages.txt

Build it:

pip install markwork furo
sphinx-build -b html docs docs/_build/html

Open docs/_build/html/index.html. One page per source file, every name a link, the test suite mirrored alongside.

The defaults assume a single package under src/ and a tests/ directory beside it; the project root is the parent of the folder holding conf.py. Override when needed:

markwork_package = "acme"      # auto-detected when src/ holds one package
markwork_src_root = "src"      # source root, relative to the project
markwork_tests_root = "tests"  # test root, relative to the project

Flat layout, with the package at the project root instead of under src/? Point the source root at the root and name the package explicitly:

markwork_src_root = "."
markwork_package = "acme"

Requires Python 3.10 or newer.

Themes

markwork is theme-independent and works with any Sphinx theme: furo, sphinx_rtd_theme, the PyData theme, the built-in alabaster, or your own. The rendered source is a stock Pygments block, so its syntax colours come from the active theme's own Pygments style, and the bundled stylesheet uses inherited and fixed colours so the go-to-definition underlines and the line-jump highlight read on a light or a dark theme alike.

These docs are built with furo as a preference, not a requirement. To preview under a different installed theme, set MARKWORK_THEME:

MARKWORK_THEME=alabaster sphinx-build -b html docs docs/_build/html

Contributing

Contributions are welcome. Open an issue or a pull request at github.com/AsgerJon/markwork.

License

markwork is released under the Apache License 2.0 (Apache-2.0). See LICENSE for the full text.

Release files for markwork 0.1.1

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for markwork 0.1.1
File Size Uploaded
markwork-0.1.1.tar.gz 37.2 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for markwork 0.1.1
File Interpreter ABI Platform
markwork-0.1.1-py3-none-any.whl Python 3 none any Details

Total release size: 68.7 kB

Release files / markwork-0.1.1.tar.gz

Download URL markwork-0.1.1.tar.gz
Size 37.2 kB
Tags Source
SHA-256 checksum
How to use checksums
f7aad4f74f652f3e997f20719b34dbce299741614a5487f4ed4d49fc2148862b
BLAKE2b-256 checksum
How to use checksums
1899bfea4153bdc005464e8d2df3e2dca254a48511df168410fb406a1b692c5f
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/6.1.0 CPython/3.13.12

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Jun 14, 2026.

Transparency log

Release files / markwork-0.1.1-py3-none-any.whl

Download URL markwork-0.1.1-py3-none-any.whl
Size 31.4 kB
Tags Python 3
SHA-256 checksum
How to use checksums
224743ac4f22e9582426c752c972b69bbae8b7b4696a1a26d65969910048a85b
BLAKE2b-256 checksum
How to use checksums
35612d5ae0201188fc88409853312cadd29cc3a25801ec4e04e8bf3a9b2699b7
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/6.1.0 CPython/3.13.12

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Jun 14, 2026.

Transparency log
Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page