jupyter-python-tutor 0.2.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- jupyter_python_tutor-0.2.0/LICENSE +21 -0
- jupyter_python_tutor-0.2.0/PKG-INFO +151 -0
- jupyter_python_tutor-0.2.0/README.md +131 -0
- jupyter_python_tutor-0.2.0/jupyter_python_tutor/__init__.py +16 -0
- jupyter_python_tutor-0.2.0/jupyter_python_tutor/magics.py +109 -0
- jupyter_python_tutor-0.2.0/jupyter_python_tutor/renderer.py +837 -0
- jupyter_python_tutor-0.2.0/jupyter_python_tutor/tracer.py +591 -0
- jupyter_python_tutor-0.2.0/jupyter_python_tutor.egg-info/PKG-INFO +151 -0
- jupyter_python_tutor-0.2.0/jupyter_python_tutor.egg-info/SOURCES.txt +15 -0
- jupyter_python_tutor-0.2.0/jupyter_python_tutor.egg-info/dependency_links.txt +1 -0
- jupyter_python_tutor-0.2.0/jupyter_python_tutor.egg-info/requires.txt +6 -0
- jupyter_python_tutor-0.2.0/jupyter_python_tutor.egg-info/top_level.txt +1 -0
- jupyter_python_tutor-0.2.0/pyproject.toml +30 -0
- jupyter_python_tutor-0.2.0/setup.cfg +4 -0
- jupyter_python_tutor-0.2.0/tests/test_magics.py +79 -0
- jupyter_python_tutor-0.2.0/tests/test_renderer.py +373 -0
- jupyter_python_tutor-0.2.0/tests/test_tracer.py +454 -0
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 dive4dec
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
|
@@ -0,0 +1,151 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: jupyter-python-tutor
|
|
3
|
+
Version: 0.2.0
|
|
4
|
+
Summary: Python Tutor-style step-by-step code visualization for JupyterLab 4.x and Notebook 7
|
|
5
|
+
Author: dive4dec
|
|
6
|
+
License-Expression: MIT
|
|
7
|
+
Project-URL: Homepage, https://github.com/dive4dec/jupyter-python-tutor
|
|
8
|
+
Project-URL: Repository, https://github.com/dive4dec/jupyter-python-tutor
|
|
9
|
+
Project-URL: Issues, https://github.com/dive4dec/jupyter-python-tutor/issues
|
|
10
|
+
Project-URL: Changelog, https://github.com/dive4dec/jupyter-python-tutor/blob/main/CHANGELOG.md
|
|
11
|
+
Requires-Python: >=3.8
|
|
12
|
+
Description-Content-Type: text/markdown
|
|
13
|
+
License-File: LICENSE
|
|
14
|
+
Requires-Dist: ipython>=8.0
|
|
15
|
+
Provides-Extra: dev
|
|
16
|
+
Requires-Dist: pytest; extra == "dev"
|
|
17
|
+
Requires-Dist: build; extra == "dev"
|
|
18
|
+
Requires-Dist: twine; extra == "dev"
|
|
19
|
+
Dynamic: license-file
|
|
20
|
+
|
|
21
|
+
# jupyter-python-tutor
|
|
22
|
+
|
|
23
|
+
Python Tutor–style step-by-step code visualization directly inside JupyterLab 4.x and Notebook 7 cells.
|
|
24
|
+
|
|
25
|
+
## Quick Start
|
|
26
|
+
|
|
27
|
+
```bash
|
|
28
|
+
pip install jupyter-python-tutor
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
In a Jupyter cell:
|
|
32
|
+
|
|
33
|
+
```python
|
|
34
|
+
%load_ext jupyter_python_tutor
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
Then use the `%%tutor` cell magic:
|
|
38
|
+
|
|
39
|
+
```python
|
|
40
|
+
%%tutor
|
|
41
|
+
x = 3
|
|
42
|
+
y = x + 4
|
|
43
|
+
print(y)
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
An interactive trace appears below the cell — drag the slider to navigate
|
|
47
|
+
through execution, see variable values change at each line, with SVG arrows
|
|
48
|
+
from frame variables to heap objects (like [Python Tutor](https://pythontutor.com)).
|
|
49
|
+
|
|
50
|
+
## Features
|
|
51
|
+
|
|
52
|
+
- **Interactive slider navigation** — drag the slider (or use ◀ ▶ buttons / ← → arrow keys) to scrub through execution steps
|
|
53
|
+
- **SVG pointer arrows** — arrows from frame variables to heap objects, like OPT_Mentor / Python Tutor
|
|
54
|
+
- **Single-step view** — only the current step is shown (not all steps stacked)
|
|
55
|
+
- **Call stack visualization** — global frame + local frames with line numbers
|
|
56
|
+
- **Heap objects** — lists, dicts, class instances, functions, and other objects shown as boxes with arrows pointing to them
|
|
57
|
+
- **Resizable columns** — drag the vertical dividers between code / variables / objects to resize; double-click a divider to collapse/expand
|
|
58
|
+
- **Auto-height** — iframe height follows the tallest column content (no fixed height, no internal scroll)
|
|
59
|
+
- **AST-based variable filtering** — only variables used by the traced code are shown (no IPython internals, no contamination from other cells)
|
|
60
|
+
- **stdout capture** — `print()` output is displayed per step
|
|
61
|
+
- **functools.wraps-safe** — functions show their true name (`__code__.co_name`), not the wrapper's `__name__`
|
|
62
|
+
- **Trusted notebook support** — renders fully (with JS, CSS, arrows) in trusted notebooks; `jupyter trust notebook.ipynb` after execution
|
|
63
|
+
- **Works with Notebook 7** — compatible with the new Jupyter Notebook 7 (JupyterLab-based)
|
|
64
|
+
- **Pure Python** — no compiled extensions, works in CPython 3.8+
|
|
65
|
+
|
|
66
|
+
## Options
|
|
67
|
+
|
|
68
|
+
```
|
|
69
|
+
%%tutor --max-steps 1000 # Limit trace steps (default: 5000)
|
|
70
|
+
%%tutor --raw # Output trace as JSON instead of HTML
|
|
71
|
+
%%tutor --height 400 # Set minimum widget height (default: 500)
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
## Examples
|
|
75
|
+
|
|
76
|
+
### Loops
|
|
77
|
+
|
|
78
|
+
```python
|
|
79
|
+
%%tutor
|
|
80
|
+
total = 0
|
|
81
|
+
for i in range(5):
|
|
82
|
+
total += i
|
|
83
|
+
print(f"Sum: {total}")
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
### Functions with recursion
|
|
87
|
+
|
|
88
|
+
```python
|
|
89
|
+
%%tutor
|
|
90
|
+
def factorial(n):
|
|
91
|
+
if n <= 1:
|
|
92
|
+
return 1
|
|
93
|
+
return n * factorial(n - 1)
|
|
94
|
+
|
|
95
|
+
result = factorial(4)
|
|
96
|
+
print(result)
|
|
97
|
+
```
|
|
98
|
+
|
|
99
|
+
### Classes and inheritance
|
|
100
|
+
|
|
101
|
+
```python
|
|
102
|
+
%%tutor
|
|
103
|
+
class Animal:
|
|
104
|
+
def __init__(self, name):
|
|
105
|
+
self.name = name
|
|
106
|
+
def speak(self):
|
|
107
|
+
return f"{self.name} says hello"
|
|
108
|
+
|
|
109
|
+
class Dog(Animal):
|
|
110
|
+
def speak(self):
|
|
111
|
+
return f"{self.name} barks"
|
|
112
|
+
|
|
113
|
+
d = Dog("Rex")
|
|
114
|
+
print(d.speak())
|
|
115
|
+
```
|
|
116
|
+
|
|
117
|
+
## How It Works
|
|
118
|
+
|
|
119
|
+
1. **Tracing**: The `%%tutor` magic compiles the cell code and executes it under
|
|
120
|
+
`sys.settrace()`. At each line/call/return event, a snapshot of all local and
|
|
121
|
+
global variables is captured. AST analysis (`ast.parse`) extracts the set of
|
|
122
|
+
names the traced code touches, so only code-relevant variables are shown
|
|
123
|
+
(filtering out IPython internals and variables from other cells).
|
|
124
|
+
|
|
125
|
+
2. **Rendering**: The trace steps are rendered as a complete HTML page inside
|
|
126
|
+
an `<iframe srcdoc="...">`. This bypasses JupyterLab 4's HTML sanitizer
|
|
127
|
+
(which strips `<script>`, `<style>`, `<button>`, `<input>`, etc. from
|
|
128
|
+
untrusted output). In trusted notebooks, the iframe renders with full
|
|
129
|
+
CSS + JavaScript — enabling slider navigation, SVG arrows, draggable
|
|
130
|
+
dividers, and auto-height.
|
|
131
|
+
|
|
132
|
+
3. **Arrows**: SVG paths are computed at render time from the bounding boxes
|
|
133
|
+
of pointer boxes (in frame variables) to heap objects. Arrows redraw on
|
|
134
|
+
slider navigation, column resize, and window resize.
|
|
135
|
+
|
|
136
|
+
4. **JupyterLab 4 compatibility**: JupyterLab 4's HTML sanitizer (DOMPurify)
|
|
137
|
+
strips JavaScript and external URLs from untrusted notebooks. The iframe
|
|
138
|
+
`srcdoc` approach bypasses this entirely in trusted notebooks. Run
|
|
139
|
+
`jupyter trust your_notebook.ipynb` after executing cells with `%%tutor`
|
|
140
|
+
to ensure the visualization renders correctly.
|
|
141
|
+
|
|
142
|
+
## Limitations
|
|
143
|
+
|
|
144
|
+
- **Trusted notebooks required** for full rendering (arrows, slider, dividers).
|
|
145
|
+
Untrusted notebooks will show a stripped-down version.
|
|
146
|
+
- `sys.settrace()` adds overhead — very long loops will be slow; use `--max-steps` to limit
|
|
147
|
+
- Threads are not traced (only the main thread)
|
|
148
|
+
|
|
149
|
+
## License
|
|
150
|
+
|
|
151
|
+
MIT
|
|
@@ -0,0 +1,131 @@
|
|
|
1
|
+
# jupyter-python-tutor
|
|
2
|
+
|
|
3
|
+
Python Tutor–style step-by-step code visualization directly inside JupyterLab 4.x and Notebook 7 cells.
|
|
4
|
+
|
|
5
|
+
## Quick Start
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
pip install jupyter-python-tutor
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
In a Jupyter cell:
|
|
12
|
+
|
|
13
|
+
```python
|
|
14
|
+
%load_ext jupyter_python_tutor
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
Then use the `%%tutor` cell magic:
|
|
18
|
+
|
|
19
|
+
```python
|
|
20
|
+
%%tutor
|
|
21
|
+
x = 3
|
|
22
|
+
y = x + 4
|
|
23
|
+
print(y)
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
An interactive trace appears below the cell — drag the slider to navigate
|
|
27
|
+
through execution, see variable values change at each line, with SVG arrows
|
|
28
|
+
from frame variables to heap objects (like [Python Tutor](https://pythontutor.com)).
|
|
29
|
+
|
|
30
|
+
## Features
|
|
31
|
+
|
|
32
|
+
- **Interactive slider navigation** — drag the slider (or use ◀ ▶ buttons / ← → arrow keys) to scrub through execution steps
|
|
33
|
+
- **SVG pointer arrows** — arrows from frame variables to heap objects, like OPT_Mentor / Python Tutor
|
|
34
|
+
- **Single-step view** — only the current step is shown (not all steps stacked)
|
|
35
|
+
- **Call stack visualization** — global frame + local frames with line numbers
|
|
36
|
+
- **Heap objects** — lists, dicts, class instances, functions, and other objects shown as boxes with arrows pointing to them
|
|
37
|
+
- **Resizable columns** — drag the vertical dividers between code / variables / objects to resize; double-click a divider to collapse/expand
|
|
38
|
+
- **Auto-height** — iframe height follows the tallest column content (no fixed height, no internal scroll)
|
|
39
|
+
- **AST-based variable filtering** — only variables used by the traced code are shown (no IPython internals, no contamination from other cells)
|
|
40
|
+
- **stdout capture** — `print()` output is displayed per step
|
|
41
|
+
- **functools.wraps-safe** — functions show their true name (`__code__.co_name`), not the wrapper's `__name__`
|
|
42
|
+
- **Trusted notebook support** — renders fully (with JS, CSS, arrows) in trusted notebooks; `jupyter trust notebook.ipynb` after execution
|
|
43
|
+
- **Works with Notebook 7** — compatible with the new Jupyter Notebook 7 (JupyterLab-based)
|
|
44
|
+
- **Pure Python** — no compiled extensions, works in CPython 3.8+
|
|
45
|
+
|
|
46
|
+
## Options
|
|
47
|
+
|
|
48
|
+
```
|
|
49
|
+
%%tutor --max-steps 1000 # Limit trace steps (default: 5000)
|
|
50
|
+
%%tutor --raw # Output trace as JSON instead of HTML
|
|
51
|
+
%%tutor --height 400 # Set minimum widget height (default: 500)
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
## Examples
|
|
55
|
+
|
|
56
|
+
### Loops
|
|
57
|
+
|
|
58
|
+
```python
|
|
59
|
+
%%tutor
|
|
60
|
+
total = 0
|
|
61
|
+
for i in range(5):
|
|
62
|
+
total += i
|
|
63
|
+
print(f"Sum: {total}")
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
### Functions with recursion
|
|
67
|
+
|
|
68
|
+
```python
|
|
69
|
+
%%tutor
|
|
70
|
+
def factorial(n):
|
|
71
|
+
if n <= 1:
|
|
72
|
+
return 1
|
|
73
|
+
return n * factorial(n - 1)
|
|
74
|
+
|
|
75
|
+
result = factorial(4)
|
|
76
|
+
print(result)
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
### Classes and inheritance
|
|
80
|
+
|
|
81
|
+
```python
|
|
82
|
+
%%tutor
|
|
83
|
+
class Animal:
|
|
84
|
+
def __init__(self, name):
|
|
85
|
+
self.name = name
|
|
86
|
+
def speak(self):
|
|
87
|
+
return f"{self.name} says hello"
|
|
88
|
+
|
|
89
|
+
class Dog(Animal):
|
|
90
|
+
def speak(self):
|
|
91
|
+
return f"{self.name} barks"
|
|
92
|
+
|
|
93
|
+
d = Dog("Rex")
|
|
94
|
+
print(d.speak())
|
|
95
|
+
```
|
|
96
|
+
|
|
97
|
+
## How It Works
|
|
98
|
+
|
|
99
|
+
1. **Tracing**: The `%%tutor` magic compiles the cell code and executes it under
|
|
100
|
+
`sys.settrace()`. At each line/call/return event, a snapshot of all local and
|
|
101
|
+
global variables is captured. AST analysis (`ast.parse`) extracts the set of
|
|
102
|
+
names the traced code touches, so only code-relevant variables are shown
|
|
103
|
+
(filtering out IPython internals and variables from other cells).
|
|
104
|
+
|
|
105
|
+
2. **Rendering**: The trace steps are rendered as a complete HTML page inside
|
|
106
|
+
an `<iframe srcdoc="...">`. This bypasses JupyterLab 4's HTML sanitizer
|
|
107
|
+
(which strips `<script>`, `<style>`, `<button>`, `<input>`, etc. from
|
|
108
|
+
untrusted output). In trusted notebooks, the iframe renders with full
|
|
109
|
+
CSS + JavaScript — enabling slider navigation, SVG arrows, draggable
|
|
110
|
+
dividers, and auto-height.
|
|
111
|
+
|
|
112
|
+
3. **Arrows**: SVG paths are computed at render time from the bounding boxes
|
|
113
|
+
of pointer boxes (in frame variables) to heap objects. Arrows redraw on
|
|
114
|
+
slider navigation, column resize, and window resize.
|
|
115
|
+
|
|
116
|
+
4. **JupyterLab 4 compatibility**: JupyterLab 4's HTML sanitizer (DOMPurify)
|
|
117
|
+
strips JavaScript and external URLs from untrusted notebooks. The iframe
|
|
118
|
+
`srcdoc` approach bypasses this entirely in trusted notebooks. Run
|
|
119
|
+
`jupyter trust your_notebook.ipynb` after executing cells with `%%tutor`
|
|
120
|
+
to ensure the visualization renders correctly.
|
|
121
|
+
|
|
122
|
+
## Limitations
|
|
123
|
+
|
|
124
|
+
- **Trusted notebooks required** for full rendering (arrows, slider, dividers).
|
|
125
|
+
Untrusted notebooks will show a stripped-down version.
|
|
126
|
+
- `sys.settrace()` adds overhead — very long loops will be slow; use `--max-steps` to limit
|
|
127
|
+
- Threads are not traced (only the main thread)
|
|
128
|
+
|
|
129
|
+
## License
|
|
130
|
+
|
|
131
|
+
MIT
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
"""jupyter-python-tutor: Python Tutor-style visualization for JupyterLab 4.x and Notebook 7.
|
|
2
|
+
|
|
3
|
+
Usage in a Jupyter cell:
|
|
4
|
+
|
|
5
|
+
%%tutor
|
|
6
|
+
x = 3
|
|
7
|
+
y = x + 4
|
|
8
|
+
print(y)
|
|
9
|
+
"""
|
|
10
|
+
from .tracer import trace_code
|
|
11
|
+
from .renderer import render_trace
|
|
12
|
+
from .magics import load_ipython_extension
|
|
13
|
+
|
|
14
|
+
__version__ = "0.2.0"
|
|
15
|
+
|
|
16
|
+
__all__ = ["trace_code", "render_trace", "load_ipython_extension"]
|
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
"""IPython cell magic for jupyter-python-tutor.
|
|
2
|
+
|
|
3
|
+
Usage in a Jupyter cell:
|
|
4
|
+
|
|
5
|
+
%%tutor
|
|
6
|
+
x = 3
|
|
7
|
+
y = x + 4
|
|
8
|
+
print(y)
|
|
9
|
+
|
|
10
|
+
Options:
|
|
11
|
+
%%tutor --max-steps 1000 — limit the number of trace steps
|
|
12
|
+
%%tutor --raw — output the trace as JSON instead of HTML
|
|
13
|
+
%%tutor --height 400 — set max-height of the variables panel (px)
|
|
14
|
+
"""
|
|
15
|
+
from __future__ import annotations
|
|
16
|
+
|
|
17
|
+
import argparse
|
|
18
|
+
import typing
|
|
19
|
+
|
|
20
|
+
from IPython.core.magic import Magics, magics_class, cell_magic
|
|
21
|
+
from IPython.display import HTML, JSON
|
|
22
|
+
|
|
23
|
+
from .tracer import trace_code
|
|
24
|
+
from .renderer import render_trace
|
|
25
|
+
|
|
26
|
+
__all__ = ["TutorMagics", "load_ipython_extension", "unload_ipython_extension"]
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
def _make_parser() -> argparse.ArgumentParser:
|
|
30
|
+
parser = argparse.ArgumentParser(
|
|
31
|
+
prog="%%tutor",
|
|
32
|
+
description="Trace Python code and display an interactive visualization.",
|
|
33
|
+
)
|
|
34
|
+
parser.add_argument(
|
|
35
|
+
"--max-steps", type=int, default=5000,
|
|
36
|
+
help="Maximum number of trace steps to capture (default: 5000)",
|
|
37
|
+
)
|
|
38
|
+
parser.add_argument(
|
|
39
|
+
"--raw", action="store_true",
|
|
40
|
+
help="Output trace as JSON instead of interactive HTML",
|
|
41
|
+
)
|
|
42
|
+
parser.add_argument(
|
|
43
|
+
"--height", type=int, default=300,
|
|
44
|
+
help="Max height of the variables panel in pixels (default: 300)",
|
|
45
|
+
)
|
|
46
|
+
return parser
|
|
47
|
+
|
|
48
|
+
|
|
49
|
+
@magics_class
|
|
50
|
+
class TutorMagics(Magics):
|
|
51
|
+
"""Register the %%tutor cell magic."""
|
|
52
|
+
|
|
53
|
+
@cell_magic("tutor")
|
|
54
|
+
def tutor(self, line: str, cell: str):
|
|
55
|
+
"""Trace the cell code and display an interactive visualization."""
|
|
56
|
+
parser = _make_parser()
|
|
57
|
+
try:
|
|
58
|
+
args = parser.parse_args(line.split() if line else [])
|
|
59
|
+
except SystemExit:
|
|
60
|
+
return
|
|
61
|
+
|
|
62
|
+
# Pass the ACTUAL user namespace (not a copy) so that:
|
|
63
|
+
# 1. Variables/classes/functions from previous cells are available
|
|
64
|
+
# 2. Variables created by the traced code persist in the kernel
|
|
65
|
+
# (just like a normal Jupyter cell)
|
|
66
|
+
# This matches how a regular cell works and how the Jupyter visual
|
|
67
|
+
# debugger operates.
|
|
68
|
+
user_ns = self.shell.user_ns
|
|
69
|
+
|
|
70
|
+
steps = trace_code(
|
|
71
|
+
cell,
|
|
72
|
+
max_steps=args.max_steps,
|
|
73
|
+
user_globals=user_ns,
|
|
74
|
+
)
|
|
75
|
+
|
|
76
|
+
if args.raw:
|
|
77
|
+
return JSON(steps)
|
|
78
|
+
else:
|
|
79
|
+
# render_trace returns an HTML string with an <iframe srcdoc="...">
|
|
80
|
+
# containing full CSS + JS for interactive visualization.
|
|
81
|
+
# The iframe approach bypasses JupyterLab's HTML sanitizer, which
|
|
82
|
+
# strips <style>, <script>, <iframe>, <input>, etc. from untrusted
|
|
83
|
+
# outputs. When the user runs the cell live, the output is trusted
|
|
84
|
+
# and the iframe renders with full interactivity (slider, SVG arrows).
|
|
85
|
+
result = render_trace(steps, source_code=cell, height=args.height)
|
|
86
|
+
import warnings
|
|
87
|
+
with warnings.catch_warnings():
|
|
88
|
+
# Suppress IPython's "Consider using IFrame instead" warning —
|
|
89
|
+
# we intentionally use HTML(iframe srcdoc) because IFrame()
|
|
90
|
+
# requires a URL, not inline HTML.
|
|
91
|
+
warnings.filterwarnings("ignore", message="Consider using IPython.display.IFrame")
|
|
92
|
+
from IPython.display import HTML, display
|
|
93
|
+
display(HTML(result))
|
|
94
|
+
|
|
95
|
+
|
|
96
|
+
def load_ipython_extension(ipython):
|
|
97
|
+
"""Load the extension in IPython/Jupyter.
|
|
98
|
+
|
|
99
|
+
Usage::
|
|
100
|
+
|
|
101
|
+
%load_ext jupyter_python_tutor
|
|
102
|
+
"""
|
|
103
|
+
ipython.register_magics(TutorMagics)
|
|
104
|
+
|
|
105
|
+
|
|
106
|
+
def unload_ipython_extension(ipython):
|
|
107
|
+
"""Unload the extension."""
|
|
108
|
+
if "tutor" in ipython.magics_manager.magics["cell"]:
|
|
109
|
+
ipython.magics_manager.magics["cell"].pop("tutor", None)
|