Write Python lecture code. Get an interactive viewer on GitHub Pages.
Project description
lectrace
Write Python lecture code. Get an interactive step-through viewer on GitHub Pages — automatically.
lectrace traces your Python code line by line using sys.settrace, captures variable state and rendered content at each step, and produces a static React app that lets anyone step through the execution with arrow keys. No Node.js, no configuration, no build step for the user — just Python.
Inspired by edtrace by Percy Liang.
Install
uv add lectrace
# or
pip install lectrace
Requires Python 3.11+. Zero mandatory dependencies — lectrace uses the standard library only. numpy, torch, and sympy are detected and rendered automatically if they are already installed in your environment.
A lecture file
A lecture is any .py file that imports from lectrace and defines a main() function:
# 01_binary_search.py
from lectrace import text, link
def binary_search(arr, target):
lo, hi = 0, len(arr) - 1
while lo <= hi: # @inspect lo hi
mid = (lo + hi) // 2 # @inspect mid
if arr[mid] == target:
return mid
elif arr[mid] < target:
lo = mid + 1
else:
hi = mid - 1
return -1
def main():
text("# Binary Search")
text("Finds a target in a sorted array in $O(\\log n)$ time.")
arr = [2, 5, 8, 12, 16, 23, 38, 42] # @inspect arr
result = binary_search(arr, 23) # @inspect result
text(f"Found 23 at index `{result}`")
link(binary_search) # click to jump to the function definition
Directives
Directives are inline comments that control tracing and display:
| Directive | Effect |
|---|---|
# @inspect x y |
Show x and y in the variable panel after this line runs |
# @clear x |
Remove x from the variable panel |
# @stepover |
Execute this line as a single step — don't trace into any calls it makes |
# @hide |
Run this line silently — never shown in the viewer |
Rendering functions
Call these anywhere inside main() or any function it calls:
| Function | What it renders |
|---|---|
text("# Heading") |
Markdown with LaTeX math ($...$ inline, $$...$$ display) |
text("...", verbatim=True) |
Monospace, whitespace preserved |
image("fig.png", width=400) |
Local file or remote URL (cached) |
video("demo.mp4") |
Embedded video with controls |
link(MyClass) |
Clickable jump to that class or function in the viewer |
link(title="Paper", url="...", authors=["Smith"], date="2024") |
Reference card with hover metadata |
plot({...}) |
Interactive Vega-Lite chart |
note("speaker annotation") |
Presenter note, hidden until N is pressed |
system_text(["python3", "--version"]) |
Shell command output as verbatim text |
Custom type rendering
Implement __lectrace__ on any class to control how it appears in the variable panel:
class Node:
def __init__(self, val, left=None, right=None):
self.val = val
self.left = left
self.right = right
def __lectrace__(self):
return {
"val": self.val,
"left": self.left.val if self.left else None,
"right": self.right.val if self.right else None,
}
Without __lectrace__, nested objects show their full repr. With it, you control exactly what students see.
File naming
| Pattern | Behaviour |
|---|---|
01_intro.py |
Lecture — appears in sidebar, traced and deployed |
02_sorting.py |
Lecture — sidebar order follows alphabetical sort |
_utils.py |
Helper — imported normally, never traced or shown |
Number prefixes control sidebar order. Helper files starting with _ are ignored by lectrace entirely.
my-course/
_data.py ← shared data, ignored by lectrace
01_intro.py ← first in sidebar
02_complexity.py ← second
03_sorting.py ← third
CLI
lectrace serve # build + serve all lectures at http://localhost:7000
lectrace serve 01_intro.py # serve a single file
lectrace build --output _site # build static site for deployment
lectrace init # generate GitHub Actions workflow + lectrace.toml
lectrace run 01_intro.py # execute and print trace stats (no server)
Deploy to GitHub Pages
lectrace init # generates .github/workflows/lectrace.yml
git add .
git commit -m "add lectures"
git push
Enable GitHub Pages in your repo settings (Source: GitHub Actions). Every push to main rebuilds and redeploys automatically.
How it works
- Tracer —
sys.settraceintercepts every line of execution. At each step it captures the call stack, inspected variable values (serialized to JSON), and any pending renderings. - Serializer — converts Python values to JSON. Primitives are direct. Collections recurse. numpy/torch/sympy are imported lazily only when encountered.
- Builder — discovers lecture files, runs each through the tracer, writes
traces/*.jsonplus atraces/index.jsonmanifest. Incremental: files are skipped if their SHA-256 hash hasn't changed. - Viewer — a pre-built React + TypeScript SPA bundled into
lectrace/_static/and shipped inside the pip package. Uses HashRouter so it works at any URL depth with zero configuration. Math via KaTeX, charts via Vega-Lite, syntax highlighting via highlight.js.
Documentation
Full documentation: https://praisegee.github.io/lectrace/
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file lectrace-1.0.8.tar.gz.
File metadata
- Download URL: lectrace-1.0.8.tar.gz
- Upload date:
- Size: 1.5 MB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
6c6fc9038bb77c987337446397e2501afd803f959fb9681d0d20364b58e0ee7a
|
|
| MD5 |
3aca6aa9778755f4690c10f7ece0a6b8
|
|
| BLAKE2b-256 |
d5850332cfb663c60e02cabe138d8b241f1a2f34302e2f3929a87aeeda95ef62
|
Provenance
The following attestation bundles were made for lectrace-1.0.8.tar.gz:
Publisher:
publish.yml on praisegee/lectrace
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
lectrace-1.0.8.tar.gz -
Subject digest:
6c6fc9038bb77c987337446397e2501afd803f959fb9681d0d20364b58e0ee7a - Sigstore transparency entry: 1373058140
- Sigstore integration time:
-
Permalink:
praisegee/lectrace@1d6adc592aba6010f0552b26fbf550483492108a -
Branch / Tag:
refs/tags/v1.0.8 - Owner: https://github.com/praisegee
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@1d6adc592aba6010f0552b26fbf550483492108a -
Trigger Event:
push
-
Statement type:
File details
Details for the file lectrace-1.0.8-py3-none-any.whl.
File metadata
- Download URL: lectrace-1.0.8-py3-none-any.whl
- Upload date:
- Size: 1.4 MB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
5cdfbf0aa1d4afbbe28b2fe9a2d0ab739ae19c9fb06fe8b03629ece867b548b1
|
|
| MD5 |
a38eb90edbbc9ad4cfc54203fb789054
|
|
| BLAKE2b-256 |
fc1c8614a9e0b7a8a66d3b23880db5fa0a52b69b12e9e88e1986098a608e0733
|
Provenance
The following attestation bundles were made for lectrace-1.0.8-py3-none-any.whl:
Publisher:
publish.yml on praisegee/lectrace
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
lectrace-1.0.8-py3-none-any.whl -
Subject digest:
5cdfbf0aa1d4afbbe28b2fe9a2d0ab739ae19c9fb06fe8b03629ece867b548b1 - Sigstore transparency entry: 1373058260
- Sigstore integration time:
-
Permalink:
praisegee/lectrace@1d6adc592aba6010f0552b26fbf550483492108a -
Branch / Tag:
refs/tags/v1.0.8 - Owner: https://github.com/praisegee
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@1d6adc592aba6010f0552b26fbf550483492108a -
Trigger Event:
push
-
Statement type: