Plain .py files as notebooks
Project description
nobook
Plain .py files as notebooks. No .ipynb files ever.
Write Python with # @block=name markers. Each block becomes a Jupyter cell. The .py file is the notebook.
File format
# @block=setup
import math
x = 42
# @block=compute
result = math.sqrt(x)
print(f"sqrt({x}) = {result:.4f}")
A block starts at # @block=name and runs until the next # @block= or end of file. That's it.
Quick start
CLI (no Jupyter needed)
uv add -e path/to/nobook
uv run nobook run example.py # executes all blocks, writes example.out.py
uv run nobook run example.py --block=setup # runs up to and including "setup"
uv run nobook list example.py # prints block names
Output goes to .out.py with results inlined as comments:
# @block=setup
import math
x = 42
# >>>
# @block=compute
result = math.sqrt(x)
print(f"sqrt({x}) = {result:.4f}")
# >>> sqrt(42) = 6.4807
Errors show as # !!! ... lines.
Jupyter
Install with the jupyter extra:
uv add -e "path/to/nobook[jupyter]"
Then launch Jupyter with the nobook ContentsManager:
uv run nobook jupyter
This runs jupyter notebook with the right --ContentsManager flag. Navigate to any .py file containing # @block= markers and it opens as a notebook. Run cells, edit, save -- it writes back to the same .py file.
Manual launch (without the CLI wrapper)
uv run jupyter notebook --ContentsManager.default_cm_class=nobook.jupyter.contentsmanager.NobookContentsManager
Minimal reproducible example
# 1. Start a new project
uv init myproject && cd myproject
# 2. Add nobook with jupyter support
uv add -e "path/to/nobook[jupyter]"
# 3. Create a nobook file
cat > demo.py << 'EOF'
# @block=hello
print("hello from nobook")
# @block=math
import math
print(f"pi = {math.pi:.4f}")
EOF
# 4. Launch
uv run nobook jupyter
Jupyter opens. Click demo.py in the file browser. It renders as a notebook with two cells (hello and math). Run them, edit them, save -- the file stays .py.
How it works
Jupyter UI (standard, unmodified)
|
IPython Kernel (standard, unmodified)
|
NobookContentsManager <-- intercepts file I/O
|
.py files with # @block markers
The NobookContentsManager subclasses Jupyter's LargeFileManager. On get(), it parses # @block= markers and returns a notebook model (blocks as code cells). On save(), it converts the notebook model back to .py format. The kernel and UI are completely stock.
.py files without # @block= markers are served normally (as plain text files).
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 nobook-0.0.1.tar.gz.
File metadata
- Download URL: nobook-0.0.1.tar.gz
- Upload date:
- Size: 129.4 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: Hatch/1.16.3 cpython/3.13.5 HTTPX/0.28.1
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
da1c30bc7fbde6b6652fadc3f4dd7f0fc07b83f8b74ded05ef364d676bcae4fe
|
|
| MD5 |
d41880146d0ba9caddfbf557a423a4f2
|
|
| BLAKE2b-256 |
3bc731e4c32415bc0d3784fc6e65e44230103efc5e1fb2708dc5300f41e4caca
|
File details
Details for the file nobook-0.0.1-py3-none-any.whl.
File metadata
- Download URL: nobook-0.0.1-py3-none-any.whl
- Upload date:
- Size: 15.8 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: Hatch/1.16.3 cpython/3.13.5 HTTPX/0.28.1
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
e926d0658f424f875ac66244dec9c8bdb05e7eea1d1ba55c5382de1dddccf9e9
|
|
| MD5 |
8607aefbb17fc94fafc0c82ea4f613c0
|
|
| BLAKE2b-256 |
4968a6298957ce91360db81d5955c9cf381fa3160b8224d5235c875ff829855b
|