Notebook files
A notebook is a Python file
Cells are comments and markdown is a function call, so python file.py runs the same code a kernel runs. Outputs never go into the file; they go into the run logs.
An example
"""Train a small model."""
import darkpyonix # preamble: runs once, before any cell
# %% Parameters [argparse]
LR = darkpyonix.params.get("lr", default=0.01, range=(0.001, 0.1, 0.001))
MODEL = darkpyonix.params.get("model", default=0, choices=["small", "large"])
# %% [markdown]
darkpyonix.markdown("""
## Training
The loop below prints one line per epoch.
""", silent=True)
# %% Train [code]
# @width: 1fr
for epoch in range(3):
print(f"epoch {epoch} lr={LR} model={MODEL}")
epoch
Lines before the first marker are the preamble. The kernel runs it once, before any cell, in every run. Keep imports and the docstring there.
.pynb has the same syntax as .py. The extension only tells an editor to open the
file as a notebook instead of as code. The kernel treats both the same.
Cell markers
- A line starting with
# %%opens a cell. The cell runs to the next marker or the end of the file. [type]sets the cell type. Without it the cell iscode.- A title may come before the type:
# %% Load data [code]. - The boundary syntax matches Jupytext's percent format. The difference is markdown: here it is a
darkpyonix.markdown()call, not a comment. - The parser works line by line, like Jupytext, so a
# %%line inside a triple-quoted string is still a marker.
Cell metadata
Lines of the form # @key: value right after a marker are that cell's metadata. A value that
parses as JSON is used as JSON; otherwise it is a string. Unknown keys are kept and ignored.
| Key | Meaning | Example |
|---|---|---|
width | Cell width in a horizontal layout (a CSS grid track) | 1fr, 320px |
layout | Layout starting at this cell | horizontal, vertical, grid |
collapsed | Shown collapsed at first | true |
auto_run | Runs when a client connects to the kernel | true |
id | A stable id a client may assign | "c-3f2a" |
Layout is display only. Cells in a horizontal layout still run one after another.
Cell types
| Type | Status | What a run does |
|---|---|---|
code | implemented | Runs the body. The value of a last expression becomes the result and is stored in _. |
markdown | implemented | Runs the darkpyonix.markdown(...) call. |
argparse | implemented | Runs darkpyonix.params.get(...) calls; clients show a form. |
binding | implemented | Re-evaluates definitions decorated with @darkpyonix.binding without access to code cell variables. |
shell | implemented | Runs darkpyonix.run_command(...) and streams its output. |
parallel, concurrent | planned #7 | Accepted and kept; runs like code for now. |
cinterop, cppinterop, rustinterop | planned #5 | Accepted and kept; the API raises NotImplementedError. |
sql, toml, yaml, json | planned #5 | Accepted and kept; runs like code for now. |
| anything else | Runs like code; the original type is kept. |
Parameters
darkpyonix.params.get(name, default=..., choices=..., range=(min, max, step), type=..., help=...)
reads a parameter. With choices, default is an index into the list.
The value comes from the run request's params first, then from --name value on
the command line, then from default. A value outside range or not in
choices fails the cell with ValueError.
That is why the same file works both ways: darkpyonix run train.py --param lr=0.02 and
uv run train.py --lr 0.02 set the same parameter.
Markdown
darkpyonix.markdown(text, silent=False) emits text/markdown in a kernel. With
silent=True the text is shown but not written to the run log. Under python file.py
it prints nothing, so the script's output does not change.
Runtime API
| Call | In a kernel | Under python file.py |
|---|---|---|
darkpyonix.markdown(text, silent=False) | text/markdown output | nothing |
darkpyonix.params.get(...) | run request params first | command-line arguments |
@darkpyonix.binding | isolated re-evaluation | the same |
darkpyonix.run_command(cmd, check=False) | output as a stream | standard output |
darkpyonix.display(obj) | display_data output | print(repr(obj)) |
darkpyonix.uv.add, darkpyonix.uv.remove | installs into the kernel's interpreter | the same |
darkpyonix.run_parallel(*aws) | gathers coroutines | the same |
Outputs also come from print, from writes to file descriptors 1 and 2 (C extensions,
subprocesses), from _repr_html_-style methods, and from matplotlib figures, which become PNG
outputs when matplotlib is installed in the kernel's interpreter.