12. Jupyter notebooks¶
sysml-jupyter-kernel runs SysML v2 in Jupyter notebooks. A notebook cell is read exactly as
the REPL reads what you type: declarations accumulate into one session model,
a bare expression is evaluated, and every % command of the prompt — instantiating, running,
debugging, sweeping, checking, rendering — works as it does there, with the model and the
runtime kept from cell to cell. Views and documents come back as rich output the notebook
renders.
The kernel is the REPL's session behind the Jupyter protocol, not a client of the
sysml-grpc service: nothing else needs to run, and the cells hold SysML, not Python. To
drive a model from Python, use the opensysml client instead; the two can
share a notebook server.
Installing¶
The kernel is a package on PyPI. Its wheel for your platform (Linux x64 and arm64, macOS
Intel and Apple Silicon, Windows x64) carries the release's sysml-jupyter-kernel binary
and registers it as a kernelspec named sysml under the Python environment it is installed
into, so one command is the whole install:
The kernelspec, with the OpenSysML mark as the kernel's icon, lives beside the package
(<prefix>/share/jupyter/kernels/sysml) and starts the bundled binary through
python -m jupyter_opensysml_kernel, so it goes wherever the package goes:
pip uninstall removes both. Run pip install with the Python that runs the notebook
server, or in the environment it runs in, and the server sees the kernel.
On a platform without a wheel, pip installs from the sdist, which carries no binary; then
install downloads the release's binary and checks it against the SHA-256 digest the
package was built with, so a mirror or a tampered download is refused before anything is
written. The same command registers the kernelspec somewhere other than the package's
prefix — for your user, or under another prefix — copying the bundled binary into it when
there is one:
python -m jupyter_opensysml_kernel install # this environment, or the user
python -m jupyter_opensysml_kernel install --sys-prefix # this environment
python -m jupyter_opensysml_kernel install --user # ~/.local/share/jupyter
python -m jupyter_opensysml_kernel install --prefix /opt/jupyter
python -m jupyter_opensysml_kernel uninstall # removes what install wrote
A sysml-jupyter-kernel you built yourself (make build-jupyter-kernel) or installed with
install.sh --tools sysml-jupyter-kernel is registered without a download:
python -m jupyter_opensysml_kernel install --binary bin/sysml-jupyter-kernel
sysml-jupyter-kernel -install # or let the binary write its own kernelspec
With conda, the same package installs from conda-forge once its recipe is accepted there
(the recipe is kept under packaging/conda); until then pip install into the conda
environment registers the kernel under that environment's prefix the same way.
Then start a notebook server and pick SysML v2 (OpenSysML) from the kernel list:
Cells¶
A cell may hold declarations, % commands and expressions, mixed. The kernel splits it as the
prompt does — a % command is one line; an expression is answered on its own once its
brackets close; declarations between them go in as one submission, as a file would — and runs
each part in order, stopping at the first that fails.
package Vehicles {
private import ScalarValues::*;
part def Wheel { attribute diameter : Real; }
part def Car {
attribute mass : Real default = 1500.0;
part wheels : Wheel[4] { attribute :>> diameter = 0.65; }
}
part sedan : Car { attribute :>> mass = 1800.0; }
}
The next cell sees Vehicles; a bare expression evaluates against the model, and the result
is the cell's output:
Redeclaring a package replaces the earlier declaration, as %load at the prompt does, and
instances built from it are rebuilt on their next use. %clear starts the session over;
%quit is noted rather than acted on — the notebook's own shutdown ends the kernel.
Everything the prompt prints is the cell's standard output. A declaration that does not parse, a command that fails, or an expression that cannot be evaluated is an error output with the prompt's message, and the cells queued behind it (as when running the whole notebook) are skipped, as notebooks expect.
As at the prompt, a failed cell does not roll the session back: what the session accepted
before the error stays, and a declaration refused for a semantic error is still in the model
with that error reported. %clear (or Restart Kernel) starts over.
Tab completes the way the prompt's completer does: % commands, their arguments,
and qualified names in the model. Shift+Tab on a name shows what
%print would print for it. A notebook runs a cell on Shift+Enter
whatever it holds; it is jupyter console that asks the kernel whether the input is
complete, and there Enter on an unfinished declaration (an unclosed brace) reads
another line rather than running it.
Rich output¶
Output that has a richer form than text is sent in that form beside the text, and the front end shows the richest it can:
| Command | Shown as |
|---|---|
%render <view> mermaid |
A Mermaid diagram (JupyterLab 4.1 and later draw it) |
%render <view> dot |
An SVG drawing when Graphviz is installed; otherwise the DOT source |
%render <view> markdown |
Rendered Markdown |
%render <view> csv, tsv |
A table, where the front end renders tables |
%render-document <doc> |
The document as rendered Markdown |
%render-document <doc> html |
The document as HTML, with the table and figure styling of the HTML backend |
%features <instance> json |
JSON, shown in the front end's tree view |
%render <view> plantuml and d2 print their source, for a tool that draws them. See
views and rendering for the forms, and the
REPL commands reference for every command.
Interrupting and restarting¶
Interrupt (the stop button, or I I) stops the cell: a run the cell
drives — %continue, %step, a sweep, a solver query — ends at its next step with KeyboardInterrupt, and
the next cell runs on with the model unchanged. A declaration being analysed or a file being
read is not interruptible and ends on its own.
Restart starts an empty session, as a fresh sysml would; Shutdown ends the
kernel. Both are the front end's, through the protocol; the kernel also ends on SIGTERM.
The bounds the REPL takes from the environment (OPENSYSML_MAX_STEPS,
OPENSYSML_MAX_ACTION_STEPS, OPENSYSML_JOBS, OPENSYSML_TOOLS and the rest) apply to the
kernel, read when it starts: set them in the environment of the notebook server. See
environment variables.
Troubleshooting¶
- The kernel is not listed.
jupyter kernelspec listshows what the server sees; the spec must be under a path on that list. The wheel registers the kernel under the prefix of thepythonthat installed it, so install with the Python that runs the notebook server, or runpython -m jupyter_opensysml_kernel install --user(or--prefix) to register it where the server looks. pip installfetched the sdist. There is no wheel for the platform, so the package carries no binary:python -m jupyter_opensysml_kernel installdownloads the release's and registers it, or--binaryregisters one built from source.- The install refuses the download. The package pins the digests of its own release and
verifies what it fetched against them; a mismatch is reported and nothing is written.
Behind a mirror, download the release asset by hand, verify it against the release's
SHA256SUMS.txt, and register it with--binary. - A cell hangs. Interrupt it. A run runs until it ends or its step budget is spent; set
OPENSYSML_MAX_ACTION_STEPSlower, or use%stepto drive it a step at a time. - Diagrams show as source. Mermaid is drawn by JupyterLab 4.1 and later, and by Notebook 7.1 and later; DOT is drawn only where Graphviz is installed on the kernel's machine.
The protocol the kernel speaks, what kernel.json holds, and every option are in the
Jupyter kernel reference.