Metadata-Version: 2.4
Name: notebook-terminal
Version: 0.3.0
Summary: A cross-platform PTY/ConPTY terminal for Jupyter with bundled xterm.js
Author: Robert Zawadzki
License: MIT
Requires-Python: >=3.9
Description-Content-Type: text/markdown
License-File: LICENSE
Requires-Dist: ipywidgets>=8.1
Requires-Dist: ipython>=8
Requires-Dist: traitlets>=5
Requires-Dist: jupyterlab_widgets<4,>=3.0
Requires-Dist: widgetsnbextension<5,>=4.0
Requires-Dist: pywinpty>=3.0.0; platform_system == "Windows"
Provides-Extra: flask
Requires-Dist: Flask>=2.3; extra == "flask"
Requires-Dist: flask-sock>=0.7; extra == "flask"
Provides-Extra: django
Requires-Dist: Django>=4.2; extra == "django"
Requires-Dist: channels>=4; extra == "django"
Provides-Extra: plotly
Requires-Dist: plotly>=5; extra == "plotly"
Provides-Extra: data
Requires-Dist: pandas>=1.5; extra == "data"
Requires-Dist: matplotlib>=3.6; extra == "data"
Provides-Extra: dev
Requires-Dist: build>=1.2; extra == "dev"
Requires-Dist: twine>=5; extra == "dev"
Requires-Dist: pytest>=8; extra == "dev"
Dynamic: license-file

# Notebook Terminal

Notebook Terminal embeds a real PTY/ConPTY terminal in Jupyter notebooks and provides reusable terminal sessions for Flask and Django.

Version 0.4.0 removes the `anywidget` dependency. The notebook frontend uses bundled xterm.js plus standard `ipywidgets` channels, so it requires no JupyterLab extension, administrator installation, HTTP server, iframe, WebSocket, CDN, or internet connection.

## Requirements

- Python 3.9+
- `ipywidgets` 8+
- Windows: `pywinpty`
- Linux/macOS: the standard POSIX PTY implementation
- A trusted notebook that permits JavaScript output

## Installation

```bash
python -m pip install notebook-terminal
```

For an offline installation, download the wheel and its dependencies on another computer and install them with `--no-index --find-links`.

## Jupyter quick start

```python
from notebook_terminal import terminal

term = terminal(height=450, interactive=True)
```

The initial banner, prompt, username, host name, and working directory are generated by the real shell process. Nothing such as `PS C:\\Users\\Admin>` is hardcoded.

```python
term.run("python --version")
term.run("git status")
```

Read-only mode:

```python
term = terminal(interactive=False)
term.run("python script.py")
```

## Python execution and rich output

```python
term.run_python("""
import pandas as pd
import matplotlib.pyplot as plt

frame = pd.DataFrame({"x": [1, 2, 3], "y": [3, 1, 4]})
display(frame)
plt.plot(frame["x"], frame["y"])
plt.show()
""", rich_output=True, clear_previous=True)
```

Rich output tabs support DataFrames, images, HTML, Plotly, and standard Jupyter widgets created with `run_kernel()`.

## Status output

```python
term.success("Code completed successfully")
term.info("Starting")
term.warning("Check configuration")
term.error("Operation failed")
```

These messages are emitted to the display output channel and are never sent to PowerShell/Bash stdin.

## History and process control

```python
term.history()
term.last_command
term.rerun()
term.clear_history()
term.interrupt()
term.restart()
term.wait_for("ready", timeout=10)
term.wait_until_idle(timeout=30)
term.clear(clear_tabs=True)
```

## Clipboard

- `Ctrl+C` copies selected terminal text.
- `Ctrl+C` without a selection interrupts the process.
- `Ctrl+V` pastes in interactive mode.

## Flask and Django

The framework-independent `TerminalSession` and WebSocket adapters remain available:

```python
from notebook_terminal.web import manager

session_id, session = manager.create(cwd=".", interactive=True)
session.run("python --version")
```

Install optional integrations:

```bash
python -m pip install "notebook-terminal[flask]"
python -m pip install "notebook-terminal[django]"
```

Flask uses `flask-sock`; Django uses Channels. Both reuse the same terminal session backend and xterm-compatible message protocol.

## How the Jupyter bridge works

The notebook frontend is made from:

1. a real PTY/ConPTY `TerminalSession`,
2. bundled xterm.js and CSS,
3. three hidden standard `ipywidgets.Textarea` channels,
4. JavaScript output that connects xterm.js to those standard widgets,
5. a kernel dispatcher that performs widget updates on the kernel event loop.

This avoids `AnyModel`, custom JupyterLab extensions, version registration errors, and the `shell_parent` ContextVar error caused by mutating widgets directly from PTY reader threads.

## Limitations

Jupyter must allow trusted JavaScript output. Some heavily restricted notebook hosts may disable JavaScript output entirely; that cannot be bypassed by a Python package without administrator support. Standard `ipywidgets` must also work.

## Build

```bash
python -m pip install build twine pytest
python -m pytest
python -m build
python -m twine check dist/*
```

## License

MIT
