Developer’s guide#
This section is for working on handcalcs itself: fixing a bug, adding a feature, adding a renderer to the package, or improving these docs.
Set up in five minutes#
handcalcs uses uv for its environment.
$ git clone https://github.com/connorferster/handcalcs.git
$ cd handcalcs
$ uv sync # creates .venv with the package (editable) and dev tools
$ uv run pytest # the whole suite runs in a few seconds
Build the docs:
$ uv run --extra doc sphinx-build -b html docs docs/_build/html
Open docs/_build/html/index.html.
The shape of the code#
src/handcalcs/
__init__.py public API: HandCalcs, handcalc, set_option, ...
config.py global configuration
interfaces/ HandCalcs, @handcalc, %%render
parsing/ source -> tree of nodes
renderers/ tree -> output (base.py is the core)
tests/ pytest suite; tests/golden holds golden files
docs/ these docs (Sphinx + MyST)
scripts/ demo and check scripts (LaTeX compile, Markdown, Excel)
Two packages do almost all the work: parsing builds the node tree, and
renderers/base.py defines how a tree is rendered. Every built-in renderer is a
subclass that registers handlers and rules; the
renderer-building guide describes that API and applies
equally to the built-in renderers.
Go deeper#
Every module, what it does, with links to the source.
From ast to handcalcs nodes: comments, commands, blocks and values.
base.py walkthrough: dispatch, precedence and parentheses, calc lines.
Supporting new Python syntax, end to end.
Suite layout, fixtures, golden files.
Building the docs, the hc-example directive and the src role.
Versioning, CI and publishing to PyPI.
Conventions#
Code is formatted with black; CI checks
uv run black src --check.Renderer branches are merged into
hc2/devduring the v2 cycle; open pull requests against it.Handlers and rules are module-level functions registered with decorators, named
render_<type>for handlers and for what they do for rules (swap_greeks,toggle_param_line). Their docstrings say what they render and why; keep that up.