Metadata-Version: 2.4
Name: jupyter-python-tutor
Version: 0.3.3
Summary: Python Tutor-style step-by-step code visualization for JupyterLab 4.x and Notebook 7
Author: dive4dec
License-Expression: MIT
Project-URL: Homepage, https://github.com/dive4dec/jupyter-python-tutor
Project-URL: Repository, https://github.com/dive4dec/jupyter-python-tutor
Project-URL: Issues, https://github.com/dive4dec/jupyter-python-tutor/issues
Project-URL: Changelog, https://github.com/dive4dec/jupyter-python-tutor/blob/main/CHANGELOG.md
Requires-Python: >=3.8
Description-Content-Type: text/markdown
License-File: LICENSE
Requires-Dist: ipython>=8.0
Provides-Extra: dev
Requires-Dist: pytest; extra == "dev"
Requires-Dist: build; extra == "dev"
Requires-Dist: twine; extra == "dev"
Dynamic: license-file

# jupyter-python-tutor

Python Tutor–style step-by-step code visualization directly inside JupyterLab 4.x and Notebook 7 cells.

## Quick Start

```bash
pip install jupyter-python-tutor
```

In a Jupyter cell:

```python
%load_ext jupyter_python_tutor
```

Then use the `%%pytutor` cell magic:

```python
%%pytutor
x = 3
y = x + 4
print(y)
```

An interactive trace appears below the cell — drag the slider to navigate
through execution, see variable values change at each line, with SVG arrows
from frame variables to heap objects (like [Python Tutor](https://pythontutor.com)).

## Features

- **Interactive slider navigation** — drag the slider (or use ◀ ▶ buttons / ← → arrow keys) to scrub through execution steps
- **SVG pointer arrows** — arrows from frame variables to heap objects, like OPT_Mentor / Python Tutor
- **Single-step view** — only the current step is shown (not all steps stacked)
- **Call stack visualization** — global frame + local frames with line numbers
- **Heap objects** — lists, dicts, class instances, functions, and other objects shown as boxes with arrows pointing to them
- **Resizable columns** — drag the vertical dividers between code / variables / objects to resize; double-click a divider to collapse/expand
- **Auto-height** — iframe height follows the tallest column content (no fixed height, no internal scroll)
- **AST-based variable filtering** — only variables used by the traced code are shown (no IPython internals, no contamination from other cells)
- **stdout capture** — `print()` output is displayed per step
- **functools.wraps-safe** — functions show their true name (`__code__.co_name`), not the wrapper's `__name__`
- **Trusted notebook support** — renders fully (with JS, CSS, arrows) in trusted notebooks; `jupyter trust notebook.ipynb` after execution
- **Works with Notebook 7** — compatible with the new Jupyter Notebook 7 (JupyterLab-based)
- **Pure Python** — no compiled extensions, works in CPython 3.8+

## Options

```
%%pytutor --max-steps 1000   # Limit trace steps (default: 5000)
%%pytutor --raw              # Output trace as JSON instead of HTML
%%pytutor --height 400       # Set minimum widget height (default: 500)
%%pytutor --input 2026       # Pre-collected input for input() calls
```

## Examples

### Loops

```python
%%pytutor
total = 0
for i in range(5):
    total += i
print(f"Sum: {total}")
```

### Functions with recursion

```python
%%pytutor
def factorial(n):
    if n <= 1:
        return 1
    return n * factorial(n - 1)

result = factorial(4)
print(result)
```

### Classes and inheritance

```python
%%pytutor
class Animal:
    def __init__(self, name):
        self.name = name
    def speak(self):
        return f"{self.name} says hello"

class Dog(Animal):
    def speak(self):
        return f"{self.name} barks"

d = Dog("Rex")
print(d.speak())
```

## How It Works

1. **Tracing**: The `%%pytutor` magic compiles the cell code and executes it under
   `sys.settrace()`. At each line/call/return event, a snapshot of all local and
   global variables is captured. AST analysis (`ast.parse`) extracts the set of
   names the traced code touches, so only code-relevant variables are shown
   (filtering out IPython internals and variables from other cells).

2. **Rendering**: The trace steps are rendered as a complete HTML page inside
   an `<iframe srcdoc="...">`. This bypasses JupyterLab 4's HTML sanitizer
   (which strips `<script>`, `<style>`, `<button>`, `<input>`, etc. from
   untrusted output). In trusted notebooks, the iframe renders with full
   CSS + JavaScript — enabling slider navigation, SVG arrows, draggable
   dividers, and auto-height.

3. **Arrows**: SVG paths are computed at render time from the bounding boxes
   of pointer boxes (in frame variables) to heap objects. Arrows redraw on
   slider navigation, column resize, and window resize.

4. **JupyterLab 4 compatibility**: JupyterLab 4's HTML sanitizer (DOMPurify)
   strips JavaScript and external URLs from untrusted notebooks. The iframe
   `srcdoc` approach bypasses this entirely in trusted notebooks. Run
   `jupyter trust your_notebook.ipynb` after executing cells with `%%pytutor`
   to ensure the visualization renders correctly.

## Limitations

- **Trusted notebooks required** for full rendering (arrows, slider, dividers).
  Untrusted notebooks will show a stripped-down version.
- `sys.settrace()` adds overhead — very long loops will be slow; use `--max-steps` to limit
- Threads are not traced (only the main thread)

## License

MIT
