Skip to main content

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

JupyterLab / Jupyter Notebook

# 1. Create a .py file with block markers
cat > demo.py << 'EOF'
# @block=hello
print("hello from nobook")

# @block=math
import math
print(f"pi = {math.pi:.4f}")
EOF

# 2. Launch Jupyter (no install needed)
uvx nobook

Jupyter opens. Right-click demo.py in the file browser and select Open as Nobook. It renders as a notebook with two cells (hello and math). Run them, edit them, save -- the file stays .py.

VS Code

Install the Nobook VS Code extension (coming soon).

Then:

  1. Open any .py file with # @block= markers
  2. Right-click and select "Open as Nobook"
  3. Or use the command palette: "Nobook: Create New Notebook"

As a project dependency

uv add nobook
uv run nobook

Opening .py files as notebooks

In JupyterLab / Jupyter Notebook, right-click any .py file and select Open as Nobook:

Right-click a .py file and select "Open as Nobook"

.py files containing # @block= markers will also auto-open as notebooks when double-clicked.

CLI commands

Launch Jupyter

uv run nobook           # launches Jupyter Notebook (default)
uv run nobook lab       # launches JupyterLab
uv run nobook jupyter   # same as default, launches Jupyter Notebook

All launch commands accept extra arguments that are passed through to Jupyter:

uv run nobook --port=9999 --no-browser
uv run nobook lab --port=9999

Run blocks without Jupyter

uv run nobook run example.py                 # execute all blocks, write example.out.py
uv run nobook run example.py --block=setup   # run up to and including "setup"
uv run nobook list example.py                # print 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. Since output and errors are plain comments, .out.py files are valid Python -- you can run them directly with python example.out.py.

See examples/ for sample input and output files.

Manual launch (without the CLI wrapper)

uv run jupyter notebook --ServerApp.contents_manager_class=nobook.jupyter.contentsmanager.NobookContentsManager

Or for JupyterLab:

uv run jupyter lab --ServerApp.contents_manager_class=nobook.jupyter.contentsmanager.NobookContentsManager

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).

JupyterLab extension

Nobook includes a JupyterLab extension that adds:

  • Launcher card -- click "Nobook" in the launcher to create a new .py notebook
  • "Open as Nobook" context menu -- right-click any .py file to open it as a notebook
  • Block name labels -- editable labels on each cell showing the @block name

The extension is bundled with the package and installs automatically.

VS Code extension

The VS Code extension provides:

  • Open .py files with # @block= markers as notebooks
  • Block name display on each cell
  • "Open as Nobook" context menu
  • "Create New Notebook" command

Install from VS Code Marketplace (coming soon).

Development

To test nobook from any project without installing it:

uv run --project <path-to-nobook> python -m nobook

Full development install

git clone <repo-url> && cd nobook
uv sync
make setup-all      # Set up both JupyterLab and VS Code extensions
make build-all      # Build both extensions

JupyterLab extension development

cd jupyterlab-ext
jlpm install
jlpm run watch

VS Code extension development

cd vscode-ext
npm install
npm run watch
# Press F5 in VS Code to launch Extension Development Host

Project structure

nobook/
├── nobook/              # Python package
├── jupyterlab-ext/      # JupyterLab extension (TypeScript)
├── vscode-ext/          # VS Code extension (TypeScript)
├── tests/               # Python tests
└── examples/            # Example notebooks

Metadata

Release files for nobook 0.0.3

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

Source distribution (sdist)

Source distribution for nobook 0.0.3
File Size Uploaded Provenance
nobook-0.0.3.tar.gz 220.1 kB Without provenance Details

Built distribution (wheel)

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

Total release size: 252.1 kB

Release files / nobook-0.0.3.tar.gz

Download URL nobook-0.0.3.tar.gz
Size 220.1 kB
Tags Source
SHA-256 checksum
How to use checksums
d12073b9a0c641a6b07bf63d241cb900bf4b0b15c7c44dd1ddaecd1bb2e0c8bf
BLAKE2b-256 checksum
How to use checksums
56d90030e171ec23c589b44735c43dae651307189d25c460e39c44ade0e69d05
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/6.1.0 CPython/3.13.12

Release files / nobook-0.0.3-py3-none-any.whl

Download URL nobook-0.0.3-py3-none-any.whl
Size 32.0 kB
Tags Python 3
SHA-256 checksum
How to use checksums
ed8105eefa43170ed2a6aa778e2f522a82c23d2620009b7bd868e624fea94965
BLAKE2b-256 checksum
How to use checksums
50bc026ff8f4011090eb5ba43ba16cd6582edfbd79a0526422cf78b79a695e5a
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/6.1.0 CPython/3.13.12

Security for nobook 0.0.3

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.

No provenance found

None of the files in this release were uploaded with provenance metadata.

A note on package security

PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.

To learn more about protecting yourself from malicious actors, visit our package security documentation.

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