Squashed commit of the following:

commit ddd4a9145fb903eba795f3dea9402268a099e651
Author: Tom <thomas.hodson@ecmwf.int>
Date:   Sun Feb 16 18:26:06 2025 +0000

    Make executable code snippets post
This commit is contained in:
Tom 2025-02-16 18:26:20 +00:00
parent 69eaa092b7
commit 7fce46d22a
4 changed files with 165 additions and 25 deletions

View File

@ -0,0 +1,99 @@
---
title: Executable code snippets in docs and HTML object representations
layout: post
excerpt: "It just looks so nice."
assets: /assets/blog/executable-code-snippets-in-docs-and-html-object-representations
thumbnail: /assets/blog/executable-code-snippets-in-docs-and-html-object-representations/thumbnail.png
social_image: /assets/blog/executable-code-snippets-in-docs-and-html-object-representations/thumbnail.png
alt:
image_class: invertable
---
Just a quick one. Lately I've started writing the documention for [a new software project involving trees](https://qubed.readthedocs.io).
While debugging that in a Jupyter notebook I made a small HTML representation of the tree that mimis the output of `tree` but using the HTML details tag so you can open and close the subtrees.
This works using by giving the object a "_repr_html_" method that returns a HTML string. If it's present, Jupyter notebooks will use the output of that instead of `repr` to display a rich version of the object in a notebook.
```python
class Title():
def __init__(self, x):
self.x = x
def _repr_html_(self):
return f"<h1>{self.x}</h1>"
```
I then set up executable code snippets in these docs so I could give code examples and not have to paste the output in myself. I'm using MyST-NB in sphinx to do this, it gives you a nicely syntax highlighted code block along with the output evaluated against the actual code. Since the NB in Myst-NB stands for notebook, it's perhaps not so surprising that the HTML inline output also works!
The overall effect looks a bit like the below but see it [in place](https://qubed.readthedocs.io) for a better idea of how it looks with proper CSS.
```python
from qubed import Qube
q = Qube.from_dict({
"class=od" : {
"expver=0001": {"param=1":{}, "param=2":{}},
"expver=0002": {"param=1":{}, "param=2":{}},
},
"class=rd" : {
"expver=0001": {"param=1":{}, "param=2":{}, "param=3":{}},
"expver=0002": {"param=1":{}, "param=2":{}},
},
})
# depth controls how much of the tree is open when rendered as html.
q.html(depth=100)
```
<div class="output text_html">
<style>
pre#qubed-tree-555631 {
font-family: monospace;
white-space: pre;
font-family: SFMono-Regular,Menlo,Monaco,Consolas,Liberation Mono,Courier New,Courier,monospace;
font-size: 12px;
line-height: 1.4;
details {
margin-left: 0;
}
summary {
list-style: none;
cursor: pointer;
text-overflow: ellipsis;
overflow: hidden;
text-wrap: nowrap;
display: block;
}
summary:hover,span.leaf:hover {
background-color: #f0f0f0;
}
details > summary::after {
content: ' ▲';
}
details:not([open]) > summary::after {
content: " ▼";
}
.leaf {
text-overflow: ellipsis;
overflow: hidden;
text-wrap: nowrap;
display: block;
}
summary::-webkit-details-marker {
display: none;
content: "";
}
}
</style>
<pre class="qubed-tree" id="qubed-tree-555631"><details open=""><summary>root</summary><details open=""><summary>├── class=od</summary><details open=""><summary>│ ├── expver=0001</summary><span class="leaf">│ │ ├── param=1</span><span class="leaf">│ │ └── param=2</span></details><details open=""><summary>│ └── expver=0002</summary><span class="leaf">│ ├── param=1</span><span class="leaf">│ └── param=2</span></details></details><details open=""><summary>└── class=rd</summary><details open=""><summary> ├── expver=0001</summary><span class="leaf"> │ ├── param=1</span><span class="leaf"> │ ├── param=2</span><span class="leaf"> │ └── param=3</span></details><details open=""><summary> └── expver=0002</summary><span class="leaf"> ├── param=1</span><span class="leaf"> └── param=2</span></details></details></details></pre></div></div>
</div>

View File

@ -32,6 +32,7 @@
--theme-model-line-color: #222;
--theme-model-bg-color: #fcfcfc;
--theme-subtle-outline: oklch(90% 0 50);
--theme-subtle-background: rgba(128, 128, 128, 0.05);
--theme-highlight-color: hsl(338, 75%, 60%);
--theme-highlight-color-transparent: hsla(338, 75%, 60%, 33%);
--theme-subtle-text-color: #606984;
@ -291,23 +292,42 @@ section.center {
margin-bottom: 1em;
}
div.CodeRay,
.wide-outside-parent {
// width: 100vw;
position: relative;
width: calc(
100vw - var(--body-margin) - var(--main-margin-left) -
var(--main-padding-left) - var(--main-padding-right)
);
pre {
white-space: pre-wrap;
div.CodeRay {
font-family: SFMono-Regular, Menlo, Monaco, Consolas, Liberation Mono,
Courier New, Courier, monospace;
font-size: 12px;
line-height: 1.4;
padding: 1em;
background-color: var(--theme-subtle-background);
border-radius: 5px;
// Override background colors from the theme.
span {
background-color: unset !important;
}
.line-numbers {
// display: none;
margin-right: 1em;
opacity: 0.3;
a {
text-decoration: none;
pre {
text-wrap: auto;
margin: 0;
}
.wide-outside-parent {
// width: 100vw;
position: relative;
width: calc(
100vw - var(--body-margin) - var(--main-margin-left) -
var(--main-padding-left) - var(--main-padding-right)
);
pre {
white-space: pre-wrap;
}
.line-numbers {
// display: none;
margin-right: 1em;
opacity: 0.3;
a {
text-decoration: none;
}
}
}
}
@ -389,6 +409,7 @@ svg {
--theme-text-color: #fcfcfc;
--theme-bg-color: #222;
--theme-subtle-outline: oklch(50% 0 50);
--theme-subtle-background: rgba(255, 255, 255, 0.05);
}
// Two main image classes are "invertable" i.e look good inverted

View File

@ -1,5 +1,16 @@
.highlight table td { padding: 5px; }
.highlight table pre { margin: 0; }
.highlight {
font-family: SFMono-Regular, Menlo, Monaco, Consolas, Liberation Mono,
Courier New, Courier, monospace;
font-size: 12px;
line-height: 1.4;
}
.highlight table td {
padding: 5px;
}
.highlight table pre {
margin: 0;
}
.highlight .cm {
color: #999988;
font-style: italic;
@ -17,7 +28,10 @@
font-weight: bold;
font-style: italic;
}
.highlight .c, .highlight .ch, .highlight .cd, .highlight .cpf {
.highlight .c,
.highlight .ch,
.highlight .cd,
.highlight .cpf {
color: #999988;
font-style: italic;
}
@ -82,7 +96,8 @@
color: #445588;
font-weight: bold;
}
.highlight .k, .highlight .kv {
.highlight .k,
.highlight .kv {
color: #000000;
font-weight: bold;
}
@ -101,7 +116,9 @@
.highlight .mo {
color: #009999;
}
.highlight .m, .highlight .mb, .highlight .mx {
.highlight .m,
.highlight .mb,
.highlight .mx {
color: #009999;
}
.highlight .sa {
@ -141,7 +158,8 @@
.highlight .ss {
color: #990073;
}
.highlight .s, .highlight .dl {
.highlight .s,
.highlight .dl {
color: #d14;
}
.highlight .na {
@ -151,7 +169,7 @@
color: #999999;
}
.highlight .nb {
color: #0086B3;
color: #0086b3;
}
.highlight .nc {
color: #445588;
@ -171,7 +189,8 @@
color: #990000;
font-weight: bold;
}
.highlight .nf, .highlight .fm {
.highlight .nf,
.highlight .fm {
color: #990000;
font-weight: bold;
}
@ -194,7 +213,8 @@
.highlight .vi {
color: #008080;
}
.highlight .nv, .highlight .vm {
.highlight .nv,
.highlight .vm {
color: #008080;
}
.highlight .ow {

Binary file not shown.

After

Width:  |  Height:  |  Size: 26 KiB