jupyter-python-tutor 0.2.0__tar.gz → 0.3.1__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 → jupyter_python_tutor-0.3.1}/PKG-INFO +12 -11
- {jupyter_python_tutor-0.2.0 → jupyter_python_tutor-0.3.1}/README.md +11 -10
- {jupyter_python_tutor-0.2.0 → jupyter_python_tutor-0.3.1}/jupyter_python_tutor/__init__.py +2 -2
- {jupyter_python_tutor-0.2.0 → jupyter_python_tutor-0.3.1}/jupyter_python_tutor/magics.py +24 -10
- {jupyter_python_tutor-0.2.0 → jupyter_python_tutor-0.3.1}/jupyter_python_tutor/renderer.py +265 -140
- {jupyter_python_tutor-0.2.0 → jupyter_python_tutor-0.3.1}/jupyter_python_tutor/tracer.py +68 -4
- {jupyter_python_tutor-0.2.0 → jupyter_python_tutor-0.3.1}/jupyter_python_tutor.egg-info/PKG-INFO +12 -11
- {jupyter_python_tutor-0.2.0 → jupyter_python_tutor-0.3.1}/pyproject.toml +1 -1
- {jupyter_python_tutor-0.2.0 → jupyter_python_tutor-0.3.1}/tests/test_magics.py +11 -11
- {jupyter_python_tutor-0.2.0 → jupyter_python_tutor-0.3.1}/tests/test_tracer.py +1 -1
- {jupyter_python_tutor-0.2.0 → jupyter_python_tutor-0.3.1}/LICENSE +0 -0
- {jupyter_python_tutor-0.2.0 → jupyter_python_tutor-0.3.1}/jupyter_python_tutor.egg-info/SOURCES.txt +0 -0
- {jupyter_python_tutor-0.2.0 → jupyter_python_tutor-0.3.1}/jupyter_python_tutor.egg-info/dependency_links.txt +0 -0
- {jupyter_python_tutor-0.2.0 → jupyter_python_tutor-0.3.1}/jupyter_python_tutor.egg-info/requires.txt +0 -0
- {jupyter_python_tutor-0.2.0 → jupyter_python_tutor-0.3.1}/jupyter_python_tutor.egg-info/top_level.txt +0 -0
- {jupyter_python_tutor-0.2.0 → jupyter_python_tutor-0.3.1}/setup.cfg +0 -0
- {jupyter_python_tutor-0.2.0 → jupyter_python_tutor-0.3.1}/tests/test_renderer.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: jupyter-python-tutor
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.3.1
|
|
4
4
|
Summary: Python Tutor-style step-by-step code visualization for JupyterLab 4.x and Notebook 7
|
|
5
5
|
Author: dive4dec
|
|
6
6
|
License-Expression: MIT
|
|
@@ -34,10 +34,10 @@ In a Jupyter cell:
|
|
|
34
34
|
%load_ext jupyter_python_tutor
|
|
35
35
|
```
|
|
36
36
|
|
|
37
|
-
Then use the `%%
|
|
37
|
+
Then use the `%%pytutor` cell magic:
|
|
38
38
|
|
|
39
39
|
```python
|
|
40
|
-
%%
|
|
40
|
+
%%pytutor
|
|
41
41
|
x = 3
|
|
42
42
|
y = x + 4
|
|
43
43
|
print(y)
|
|
@@ -66,9 +66,10 @@ from frame variables to heap objects (like [Python Tutor](https://pythontutor.co
|
|
|
66
66
|
## Options
|
|
67
67
|
|
|
68
68
|
```
|
|
69
|
-
%%
|
|
70
|
-
%%
|
|
71
|
-
%%
|
|
69
|
+
%%pytutor --max-steps 1000 # Limit trace steps (default: 5000)
|
|
70
|
+
%%pytutor --raw # Output trace as JSON instead of HTML
|
|
71
|
+
%%pytutor --height 400 # Set minimum widget height (default: 500)
|
|
72
|
+
%%pytutor --input 2026 # Pre-collected input for input() calls
|
|
72
73
|
```
|
|
73
74
|
|
|
74
75
|
## Examples
|
|
@@ -76,7 +77,7 @@ from frame variables to heap objects (like [Python Tutor](https://pythontutor.co
|
|
|
76
77
|
### Loops
|
|
77
78
|
|
|
78
79
|
```python
|
|
79
|
-
%%
|
|
80
|
+
%%pytutor
|
|
80
81
|
total = 0
|
|
81
82
|
for i in range(5):
|
|
82
83
|
total += i
|
|
@@ -86,7 +87,7 @@ print(f"Sum: {total}")
|
|
|
86
87
|
### Functions with recursion
|
|
87
88
|
|
|
88
89
|
```python
|
|
89
|
-
%%
|
|
90
|
+
%%pytutor
|
|
90
91
|
def factorial(n):
|
|
91
92
|
if n <= 1:
|
|
92
93
|
return 1
|
|
@@ -99,7 +100,7 @@ print(result)
|
|
|
99
100
|
### Classes and inheritance
|
|
100
101
|
|
|
101
102
|
```python
|
|
102
|
-
%%
|
|
103
|
+
%%pytutor
|
|
103
104
|
class Animal:
|
|
104
105
|
def __init__(self, name):
|
|
105
106
|
self.name = name
|
|
@@ -116,7 +117,7 @@ print(d.speak())
|
|
|
116
117
|
|
|
117
118
|
## How It Works
|
|
118
119
|
|
|
119
|
-
1. **Tracing**: The `%%
|
|
120
|
+
1. **Tracing**: The `%%pytutor` magic compiles the cell code and executes it under
|
|
120
121
|
`sys.settrace()`. At each line/call/return event, a snapshot of all local and
|
|
121
122
|
global variables is captured. AST analysis (`ast.parse`) extracts the set of
|
|
122
123
|
names the traced code touches, so only code-relevant variables are shown
|
|
@@ -136,7 +137,7 @@ print(d.speak())
|
|
|
136
137
|
4. **JupyterLab 4 compatibility**: JupyterLab 4's HTML sanitizer (DOMPurify)
|
|
137
138
|
strips JavaScript and external URLs from untrusted notebooks. The iframe
|
|
138
139
|
`srcdoc` approach bypasses this entirely in trusted notebooks. Run
|
|
139
|
-
`jupyter trust your_notebook.ipynb` after executing cells with `%%
|
|
140
|
+
`jupyter trust your_notebook.ipynb` after executing cells with `%%pytutor`
|
|
140
141
|
to ensure the visualization renders correctly.
|
|
141
142
|
|
|
142
143
|
## Limitations
|
|
@@ -14,10 +14,10 @@ In a Jupyter cell:
|
|
|
14
14
|
%load_ext jupyter_python_tutor
|
|
15
15
|
```
|
|
16
16
|
|
|
17
|
-
Then use the `%%
|
|
17
|
+
Then use the `%%pytutor` cell magic:
|
|
18
18
|
|
|
19
19
|
```python
|
|
20
|
-
%%
|
|
20
|
+
%%pytutor
|
|
21
21
|
x = 3
|
|
22
22
|
y = x + 4
|
|
23
23
|
print(y)
|
|
@@ -46,9 +46,10 @@ from frame variables to heap objects (like [Python Tutor](https://pythontutor.co
|
|
|
46
46
|
## Options
|
|
47
47
|
|
|
48
48
|
```
|
|
49
|
-
%%
|
|
50
|
-
%%
|
|
51
|
-
%%
|
|
49
|
+
%%pytutor --max-steps 1000 # Limit trace steps (default: 5000)
|
|
50
|
+
%%pytutor --raw # Output trace as JSON instead of HTML
|
|
51
|
+
%%pytutor --height 400 # Set minimum widget height (default: 500)
|
|
52
|
+
%%pytutor --input 2026 # Pre-collected input for input() calls
|
|
52
53
|
```
|
|
53
54
|
|
|
54
55
|
## Examples
|
|
@@ -56,7 +57,7 @@ from frame variables to heap objects (like [Python Tutor](https://pythontutor.co
|
|
|
56
57
|
### Loops
|
|
57
58
|
|
|
58
59
|
```python
|
|
59
|
-
%%
|
|
60
|
+
%%pytutor
|
|
60
61
|
total = 0
|
|
61
62
|
for i in range(5):
|
|
62
63
|
total += i
|
|
@@ -66,7 +67,7 @@ print(f"Sum: {total}")
|
|
|
66
67
|
### Functions with recursion
|
|
67
68
|
|
|
68
69
|
```python
|
|
69
|
-
%%
|
|
70
|
+
%%pytutor
|
|
70
71
|
def factorial(n):
|
|
71
72
|
if n <= 1:
|
|
72
73
|
return 1
|
|
@@ -79,7 +80,7 @@ print(result)
|
|
|
79
80
|
### Classes and inheritance
|
|
80
81
|
|
|
81
82
|
```python
|
|
82
|
-
%%
|
|
83
|
+
%%pytutor
|
|
83
84
|
class Animal:
|
|
84
85
|
def __init__(self, name):
|
|
85
86
|
self.name = name
|
|
@@ -96,7 +97,7 @@ print(d.speak())
|
|
|
96
97
|
|
|
97
98
|
## How It Works
|
|
98
99
|
|
|
99
|
-
1. **Tracing**: The `%%
|
|
100
|
+
1. **Tracing**: The `%%pytutor` magic compiles the cell code and executes it under
|
|
100
101
|
`sys.settrace()`. At each line/call/return event, a snapshot of all local and
|
|
101
102
|
global variables is captured. AST analysis (`ast.parse`) extracts the set of
|
|
102
103
|
names the traced code touches, so only code-relevant variables are shown
|
|
@@ -116,7 +117,7 @@ print(d.speak())
|
|
|
116
117
|
4. **JupyterLab 4 compatibility**: JupyterLab 4's HTML sanitizer (DOMPurify)
|
|
117
118
|
strips JavaScript and external URLs from untrusted notebooks. The iframe
|
|
118
119
|
`srcdoc` approach bypasses this entirely in trusted notebooks. Run
|
|
119
|
-
`jupyter trust your_notebook.ipynb` after executing cells with `%%
|
|
120
|
+
`jupyter trust your_notebook.ipynb` after executing cells with `%%pytutor`
|
|
120
121
|
to ensure the visualization renders correctly.
|
|
121
122
|
|
|
122
123
|
## Limitations
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
Usage in a Jupyter cell:
|
|
4
4
|
|
|
5
|
-
%%
|
|
5
|
+
%%pytutor
|
|
6
6
|
x = 3
|
|
7
7
|
y = x + 4
|
|
8
8
|
print(y)
|
|
@@ -11,6 +11,6 @@ from .tracer import trace_code
|
|
|
11
11
|
from .renderer import render_trace
|
|
12
12
|
from .magics import load_ipython_extension
|
|
13
13
|
|
|
14
|
-
__version__ = "0.
|
|
14
|
+
__version__ = "0.3.1"
|
|
15
15
|
|
|
16
16
|
__all__ = ["trace_code", "render_trace", "load_ipython_extension"]
|
|
@@ -2,15 +2,16 @@
|
|
|
2
2
|
|
|
3
3
|
Usage in a Jupyter cell:
|
|
4
4
|
|
|
5
|
-
%%
|
|
5
|
+
%%pytutor
|
|
6
6
|
x = 3
|
|
7
7
|
y = x + 4
|
|
8
8
|
print(y)
|
|
9
9
|
|
|
10
10
|
Options:
|
|
11
|
-
%%
|
|
12
|
-
%%
|
|
13
|
-
%%
|
|
11
|
+
%%pytutor --max-steps 1000 — limit the number of trace steps
|
|
12
|
+
%%pytutor --raw — output the trace as JSON instead of HTML
|
|
13
|
+
%%pytutor --height 400 — set max-height of the variables panel (px)
|
|
14
|
+
%%pytutor --input 2026 — pre-collected input for input() calls
|
|
14
15
|
"""
|
|
15
16
|
from __future__ import annotations
|
|
16
17
|
|
|
@@ -28,7 +29,7 @@ __all__ = ["TutorMagics", "load_ipython_extension", "unload_ipython_extension"]
|
|
|
28
29
|
|
|
29
30
|
def _make_parser() -> argparse.ArgumentParser:
|
|
30
31
|
parser = argparse.ArgumentParser(
|
|
31
|
-
prog="%%
|
|
32
|
+
prog="%%pytutor",
|
|
32
33
|
description="Trace Python code and display an interactive visualization.",
|
|
33
34
|
)
|
|
34
35
|
parser.add_argument(
|
|
@@ -43,15 +44,21 @@ def _make_parser() -> argparse.ArgumentParser:
|
|
|
43
44
|
"--height", type=int, default=300,
|
|
44
45
|
help="Max height of the variables panel in pixels (default: 300)",
|
|
45
46
|
)
|
|
47
|
+
parser.add_argument(
|
|
48
|
+
"--input", action="append", default=[], metavar="VALUE",
|
|
49
|
+
help="Pre-collected input for input() calls. "
|
|
50
|
+
"Repeat --input for multiple values: --input 2026 --input John. "
|
|
51
|
+
"If omitted and code contains input(), a dialog prompts for values.",
|
|
52
|
+
)
|
|
46
53
|
return parser
|
|
47
54
|
|
|
48
55
|
|
|
49
56
|
@magics_class
|
|
50
57
|
class TutorMagics(Magics):
|
|
51
|
-
"""Register the %%
|
|
58
|
+
"""Register the %%pytutor cell magic."""
|
|
52
59
|
|
|
53
|
-
@cell_magic("
|
|
54
|
-
def
|
|
60
|
+
@cell_magic("pytutor")
|
|
61
|
+
def pytutor(self, line: str, cell: str):
|
|
55
62
|
"""Trace the cell code and display an interactive visualization."""
|
|
56
63
|
parser = _make_parser()
|
|
57
64
|
try:
|
|
@@ -67,10 +74,17 @@ class TutorMagics(Magics):
|
|
|
67
74
|
# debugger operates.
|
|
68
75
|
user_ns = self.shell.user_ns
|
|
69
76
|
|
|
77
|
+
# Pre-collected inputs for input() calls.
|
|
78
|
+
# If --input is provided, use those values.
|
|
79
|
+
# If not provided but code contains input(), use empty list
|
|
80
|
+
# (input() returns empty string instead of blocking).
|
|
81
|
+
inputs = args.input if args.input else None
|
|
82
|
+
|
|
70
83
|
steps = trace_code(
|
|
71
84
|
cell,
|
|
72
85
|
max_steps=args.max_steps,
|
|
73
86
|
user_globals=user_ns,
|
|
87
|
+
inputs=inputs,
|
|
74
88
|
)
|
|
75
89
|
|
|
76
90
|
if args.raw:
|
|
@@ -105,5 +119,5 @@ def load_ipython_extension(ipython):
|
|
|
105
119
|
|
|
106
120
|
def unload_ipython_extension(ipython):
|
|
107
121
|
"""Unload the extension."""
|
|
108
|
-
if "
|
|
109
|
-
ipython.magics_manager.magics["cell"].pop("
|
|
122
|
+
if "pytutor" in ipython.magics_manager.magics["cell"]:
|
|
123
|
+
ipython.magics_manager.magics["cell"].pop("pytutor", None)
|