Skip to content

Commit 79ade20

Browse files
committed
feat: add jupyter-sphinx support
1 parent 8ac645f commit 79ade20

File tree

5 files changed

+533
-6
lines changed

5 files changed

+533
-6
lines changed

docs/conf.py

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -51,9 +51,7 @@
5151

5252
nbsphinx_requirejs_path = ""
5353
jupyter_sphinx_require_url = ""
54-
jupyter_sphinx_thebelab_config = {
55-
"requestKernel": True,
56-
}
54+
5755

5856
# -- Options for Markdown files ----------------------------------------------
5957
# https://myst-parser.readthedocs.io/en/latest/sphinx/reference.html

docs/extensions/jupyter-sphinx.md

Lines changed: 347 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,350 @@
11
# jupyter-sphinx
22

3-
```{todo}
4-
Support this extension.
3+
Sphinx extension that executes embedded code in a Jupyter kernel and embeds outputs in the document.
4+
5+
- **Documentation**: [jupyter-sphinx.readthedocs.io](https://jupyter-sphinx.readthedocs.io/)
6+
- **Source Code**: [github.com/jupyter/jupyter-sphinx](https://github.com/jupyter/jupyter-sphinx)
7+
8+
```{eval-rst}
9+
10+
Basic Usage
11+
-----------
12+
13+
Use the ``jupyter-execute`` directive to embed executable code:
14+
15+
.. jupyter-execute::
16+
17+
name = 'world'
18+
print('hello ' + name + '!')
19+
20+
All cells share the same kernel, so variables persist across cells:
21+
22+
.. jupyter-execute::
23+
24+
a = 1
25+
print('first cell: a = {}'.format(a))
26+
27+
.. jupyter-execute::
28+
29+
a += 1
30+
print('second cell: a = {}'.format(a))
31+
32+
33+
Rich Output
34+
-----------
35+
36+
Plots
37+
^^^^^
38+
39+
.. jupyter-execute::
40+
41+
import numpy as np
42+
from matplotlib import pyplot
43+
%matplotlib inline
44+
45+
x = np.linspace(1E-3, 2 * np.pi)
46+
pyplot.plot(x, np.sin(x) / x)
47+
pyplot.plot(x, np.cos(x))
48+
pyplot.grid()
49+
50+
LaTeX
51+
^^^^^
52+
53+
.. jupyter-execute::
54+
55+
from IPython.display import Latex
56+
Latex(r'\int_{-\infty}^\infty e^{-x^2}dx = \sqrt{\pi}')
57+
58+
59+
Widgets
60+
-------
61+
62+
Interactive widgets rendered via ipywidgets.
63+
64+
.. jupyter-execute::
65+
66+
import ipywidgets as w
67+
from IPython.display import display
68+
69+
70+
Numeric
71+
^^^^^^^
72+
73+
Sliders
74+
"""""""
75+
76+
.. jupyter-execute::
77+
78+
display(
79+
w.IntSlider(value=5, min=0, max=10, description='IntSlider:'),
80+
w.IntRangeSlider(value=[3, 7], min=0, max=10, description='Range:'),
81+
)
82+
83+
Progress Bars
84+
"""""""""""""
85+
86+
.. jupyter-execute::
87+
88+
display(
89+
w.IntProgress(value=7, min=0, max=10, description='Default:'),
90+
w.IntProgress(value=5, min=0, max=10, description='Info:', bar_style='info'),
91+
w.IntProgress(value=8, min=0, max=10, description='Success:', bar_style='success'),
92+
w.IntProgress(value=3, min=0, max=10, description='Warning:', bar_style='warning'),
93+
w.IntProgress(value=6, min=0, max=10, description='Danger:', bar_style='danger'),
94+
)
95+
96+
Boolean
97+
^^^^^^^
98+
99+
.. jupyter-execute::
100+
101+
display(
102+
w.Checkbox(value=True, description='Checkbox'),
103+
w.ToggleButton(value=False, description='Toggle', icon='check'),
104+
w.Valid(value=True, description='Valid'),
105+
w.Valid(value=False, description='Invalid'),
106+
)
107+
108+
Selection
109+
^^^^^^^^^
110+
111+
.. jupyter-execute::
112+
113+
options = ['Option A', 'Option B', 'Option C']
114+
display(
115+
w.Dropdown(options=options, value='Option A', description='Dropdown:'),
116+
w.RadioButtons(options=options, description='Radio:'),
117+
w.Select(options=options, description='Select:', rows=3),
118+
w.SelectMultiple(options=options, value=['Option A'], description='Multi:', rows=3),
119+
w.ToggleButtons(options=options, description='Toggles:'),
120+
w.SelectionSlider(options=options, description='Slider:'),
121+
)
122+
123+
String
124+
^^^^^^
125+
126+
.. jupyter-execute::
127+
128+
display(
129+
w.Text(value='Hello', description='Text:'),
130+
w.Textarea(value='Multi-line\ntext input', description='Textarea:'),
131+
w.Password(value='secret', description='Password:'),
132+
w.Combobox(value='', placeholder='Type or select', options=['Apple', 'Banana'], description='Combobox:'),
133+
)
134+
135+
Buttons
136+
^^^^^^^
137+
138+
.. jupyter-execute::
139+
140+
display(
141+
w.HBox([
142+
w.Button(description='Default'),
143+
w.Button(description='Primary', button_style='primary'),
144+
w.Button(description='Success', button_style='success'),
145+
w.Button(description='Info', button_style='info'),
146+
w.Button(description='Warning', button_style='warning'),
147+
w.Button(description='Danger', button_style='danger'),
148+
]),
149+
w.HBox([
150+
w.Button(description='', icon='home', tooltip='Home'),
151+
w.Button(description='', icon='search', tooltip='Search'),
152+
w.Button(description='', icon='cog', tooltip='Settings'),
153+
w.Button(description='', icon='download', tooltip='Download'),
154+
]),
155+
)
156+
157+
Date & Color
158+
^^^^^^^^^^^^
159+
160+
.. jupyter-execute::
161+
162+
display(
163+
w.DatePicker(description='Date:'),
164+
w.ColorPicker(value='#3b82f6', description='Color:'),
165+
)
166+
167+
File Upload
168+
^^^^^^^^^^^
169+
170+
.. jupyter-execute::
171+
172+
display(
173+
w.FileUpload(accept='.txt', description='Upload'),
174+
)
175+
176+
Play / Animation
177+
^^^^^^^^^^^^^^^^
178+
179+
.. jupyter-execute::
180+
181+
play = w.Play(value=0, min=0, max=100, step=1, interval=100, description='Play:')
182+
slider = w.IntSlider(value=0, min=0, max=100, description='Value:')
183+
w.jslink((play, 'value'), (slider, 'value'))
184+
display(w.HBox([play, slider]))
185+
186+
Containers
187+
^^^^^^^^^^
188+
189+
Accordion
190+
"""""""""
191+
192+
.. jupyter-execute::
193+
194+
display(w.Accordion(children=[
195+
w.Label('Content of section one'),
196+
w.Label('Content of section two'),
197+
], titles=['Section 1', 'Section 2']))
198+
199+
Tabs
200+
""""
201+
202+
.. jupyter-execute::
203+
204+
display(w.Tab(children=[
205+
w.Label('Content of tab one'),
206+
w.Label('Content of tab two'),
207+
], titles=['Tab 1', 'Tab 2']))
208+
209+
Tags Input
210+
^^^^^^^^^^
211+
212+
.. jupyter-execute::
213+
214+
display(w.TagsInput(value=['python', 'jupyter', 'widgets'], allowed_tags=['python', 'jupyter', 'widgets', 'sphinx']))
215+
216+
Linked Widgets
217+
^^^^^^^^^^^^^^
218+
219+
.. jupyter-execute::
220+
221+
slider = w.IntSlider(description='Value:', min=0, max=100, value=50)
222+
progress = w.IntProgress(description='Progress:', min=0, max=100)
223+
text = w.IntText(description='Number:')
224+
w.jslink((slider, 'value'), (progress, 'value'))
225+
w.jslink((slider, 'value'), (text, 'value'))
226+
display(w.VBox([slider, progress, text]))
227+
228+
229+
Directive Options
230+
-----------------
231+
232+
Hide Code
233+
^^^^^^^^^
234+
235+
Use ``:hide-code:`` to show only output:
236+
237+
.. jupyter-execute::
238+
:hide-code:
239+
240+
print('this code is invisible')
241+
242+
Hide Output
243+
^^^^^^^^^^^
244+
245+
Use ``:hide-output:`` to show only code:
246+
247+
.. jupyter-execute::
248+
:hide-output:
249+
250+
print('this output is invisible')
251+
252+
Code Below
253+
^^^^^^^^^^
254+
255+
Use ``:code-below:`` to display code after output:
256+
257+
.. jupyter-execute::
258+
:code-below:
259+
260+
print('this code is below the output')
261+
262+
Line Numbers
263+
^^^^^^^^^^^^
264+
265+
Use ``:linenos:`` to add line numbers:
266+
267+
.. jupyter-execute::
268+
:linenos:
269+
270+
print('A')
271+
print('B')
272+
print('C')
273+
274+
Use ``:lineno-start:`` to start from a specific line:
275+
276+
.. jupyter-execute::
277+
:lineno-start: 7
278+
279+
print('A')
280+
print('B')
281+
print('C')
282+
283+
Emphasize Lines
284+
^^^^^^^^^^^^^^^
285+
286+
Use ``:emphasize-lines:`` to highlight specific lines:
287+
288+
.. jupyter-execute::
289+
:linenos:
290+
:emphasize-lines: 2,5-6
291+
292+
d = {
293+
'a': 1,
294+
'b': 2,
295+
'c': 3,
296+
'd': 4,
297+
'e': 5,
298+
}
299+
300+
301+
Exception Handling
302+
------------------
303+
304+
Use ``:raises:`` to display tracebacks as output instead of failing the build:
305+
306+
.. jupyter-execute::
307+
:raises:
308+
309+
1 / 0
310+
311+
Specify exception types to catch only specific errors:
312+
313+
.. jupyter-execute::
314+
:raises: KeyError, ValueError
315+
316+
a = {'hello': 'world!'}
317+
a['jello']
318+
319+
stderr Output
320+
^^^^^^^^^^^^^
321+
322+
Use ``:stderr:`` to display stderr output without build warnings:
323+
324+
.. jupyter-execute::
325+
:stderr:
326+
327+
import sys
328+
print("hello, world!", file=sys.stderr)
329+
330+
331+
Manual Cells
332+
------------
333+
334+
Use ``jupyter-input`` and ``jupyter-output`` for non-executed code samples:
335+
336+
.. jupyter-input::
337+
:linenos:
338+
339+
import time
340+
341+
def slow_print(str):
342+
time.sleep(4000) # Simulate an expensive process
343+
print(str)
344+
345+
slow_print("hello, world!")
346+
347+
.. jupyter-output::
348+
349+
hello, world!
5350
```

src/sphinx_breeze_theme/assets/styles/breeze.css

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,7 @@
5959
@import "./extensions/design.css";
6060
@import "./extensions/mermaid.css";
6161
@import "./extensions/nbsphinx.css";
62+
@import "./extensions/jupyter.css";
6263
@import "./extensions/datatables.css";
6364
@import "./extensions/docsearch.css";
6465
@import "./extensions/copybutton.css";

src/sphinx_breeze_theme/assets/styles/components/sidebar-nav.css

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,7 @@
5050
}
5151

5252
details:open {
53-
margin-top: .325rem;
53+
margin-block: .25rem .375rem;
5454

5555
> summary::after {
5656
transform: rotate(90deg);

0 commit comments

Comments
 (0)