Skip to content

Commit b6b03ab

Browse files
committed
Refactor DataLab kernel to use xeus-python backend for improved performance and debugging support; update installation instructions and add startup script for namespace injection.
1 parent 731650e commit b6b03ab

File tree

8 files changed

+478
-135
lines changed

8 files changed

+478
-135
lines changed

README.md

Lines changed: 29 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ It enables scientists and engineers to:
2020
- share notebooks that can be replayed **with or without DataLab**,
2121
- combine narrative, code, and results without sacrificing interactive visualization.
2222

23-
DataLab-Kernel is **not** a replacement for DataLab’s GUI.
23+
DataLab-Kernel is **not** a replacement for DataLab’s GUI.
2424
It is a **complementary execution layer** that turns DataLab into a hybrid scientific platform:
2525
**GUI-driven when needed, notebook-driven when appropriate.**
2626

@@ -97,15 +97,43 @@ Two connection methods are supported:
9797

9898
```bash
9999
pip install datalab-kernel sigima
100+
python -m datalab_kernel install
100101
jupyter lab
101102
```
102103

103104
Then select **DataLab Kernel** from the kernel list.
104105

106+
### Dependencies
107+
108+
DataLab-Kernel uses **xeus-python** as its backend, which provides:
109+
110+
- Improved performance compared to ipykernel
111+
- Native debugger support
112+
- JupyterLite compatibility
113+
- Better Qt event loop integration
114+
115+
The kernel requires:
116+
117+
- `xeus-python>=0.17.0` - The xeus-based Python kernel
118+
- `xeus-python-shell>=0.6.0` - Python shell utilities for xeus-python
119+
- `sigima>=1.0` - Scientific signal and image processing
120+
- `numpy>=1.22`, `h5py>=3.0`, `matplotlib>=3.5`
121+
105122
### With DataLab
106123

107124
When installed alongside DataLab, the kernel is automatically available and can be launched directly from the DataLab interface.
108125

126+
### Installing from conda-forge (recommended)
127+
128+
For best compatibility, especially on Windows:
129+
130+
```bash
131+
mamba create -n datalab-kernel
132+
mamba activate datalab-kernel
133+
mamba install xeus-python datalab-kernel -c conda-forge
134+
python -m datalab_kernel install
135+
```
136+
109137
---
110138

111139
## Persistence and Sharing

datalab_kernel/__init__.py

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,12 @@
88
A standalone Jupyter kernel providing seamless, reproducible access to DataLab
99
workspaces, with optional live synchronization to the DataLab GUI.
1010
11+
This kernel uses **xeus-python** as its backend for:
12+
- Improved performance compared to ipykernel
13+
- Native debugger support
14+
- JupyterLite compatibility
15+
- Better Qt event loop integration
16+
1117
Main components:
1218
- `workspace`: Data access and persistence API
1319
- `plotter`: Visualization frontend

datalab_kernel/__main__.py

Lines changed: 47 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
Supports running as:
88
python -m datalab_kernel install
99
python -m datalab_kernel uninstall
10+
python -m datalab_kernel (launches kernel)
1011
"""
1112

1213
from __future__ import annotations
@@ -23,15 +24,54 @@ def main() -> None:
2324
install_main()
2425
else:
2526
# Launch kernel (default behavior when run by Jupyter)
26-
# Delayed import: only needed when launching as kernel
27-
from ipykernel.kernelapp import ( # pylint: disable=import-outside-toplevel
28-
IPKernelApp,
29-
)
27+
# With xeus-python, we need to inject our namespace and then
28+
# let xeus-python handle the kernel protocol
3029

31-
# pylint: disable-next=import-outside-toplevel
32-
from datalab_kernel.kernel import DataLabKernel
30+
# First, set up the environment to indicate we want DataLab startup
31+
import os
3332

34-
IPKernelApp.launch_instance(kernel_class=DataLabKernel)
33+
os.environ["DATALAB_KERNEL_STARTUP"] = "1"
34+
35+
try:
36+
# Try to use xeus-python's native launch
37+
# xeus-python installs an 'xpython' executable
38+
import subprocess
39+
40+
xpython = subprocess.run(
41+
["xpython", "--version"],
42+
capture_output=True,
43+
text=True,
44+
)
45+
46+
if xpython.returncode == 0:
47+
# xpython is available, use it
48+
# Pass through all arguments
49+
args = ["xpython"] + sys.argv[1:]
50+
subprocess.run(args)
51+
else:
52+
raise FileNotFoundError("xpython not found")
53+
54+
except (FileNotFoundError, subprocess.SubprocessError):
55+
# xpython not available, try Python module approach
56+
try:
57+
# Import xeus-python's main entry point
58+
import xeus_python
59+
60+
# Set up our namespace first
61+
from datalab_kernel.startup import run_startup
62+
63+
run_startup()
64+
65+
# Now launch xeus-python
66+
xeus_python.main()
67+
68+
except ImportError as e:
69+
print(
70+
f"Error: xeus-python is required but not installed: {e}\n"
71+
"Install with: pip install xeus-python xeus-python-shell",
72+
file=sys.stderr,
73+
)
74+
sys.exit(1)
3575

3676

3777
if __name__ == "__main__":

datalab_kernel/install.py

Lines changed: 129 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -6,35 +6,88 @@
66
==================================
77
88
This module provides commands to install and uninstall the DataLab kernel.
9+
The kernel uses xeus-python as its backend with a custom startup script
10+
for injecting the DataLab namespace.
911
"""
1012

1113
from __future__ import annotations
1214

1315
import argparse
1416
import json
17+
import os
1518
import shutil
1619
import sys
1720
from pathlib import Path
1821

1922
KERNEL_NAME = "datalab-kernel"
2023
KERNEL_DISPLAY_NAME = "DataLab"
2124

25+
# Startup script content that will be executed when the kernel starts
26+
STARTUP_SCRIPT_CONTENT = """\
27+
# DataLab Kernel Startup Script
28+
# This file is auto-generated - do not edit manually
29+
30+
# Import and run the DataLab startup
31+
from datalab_kernel.startup import run_startup
32+
run_startup()
33+
"""
34+
35+
36+
def get_xpython_executable() -> str:
37+
"""Find the xpython executable path.
38+
39+
Returns:
40+
Path to xpython executable, or fallback to python -m approach.
41+
"""
42+
# Try to find xpython in PATH
43+
xpython_path = shutil.which("xpython")
44+
if xpython_path:
45+
return xpython_path
46+
47+
# Fallback: use Python module approach
48+
# xeus-python can be run via its Python extension module
49+
return sys.executable
50+
2251

2352
def get_kernel_spec() -> dict:
24-
"""Generate the kernel.json specification."""
25-
return {
26-
"argv": [
53+
"""Generate the kernel.json specification for xeus-python.
54+
55+
The kernel spec tells Jupyter how to launch the kernel. For xeus-python,
56+
we use the xpython executable if available, otherwise fall back to
57+
launching via Python.
58+
"""
59+
xpython = get_xpython_executable()
60+
61+
if xpython == sys.executable:
62+
# Use Python module approach for xeus-python
63+
# This works when xeus-python is installed as a wheel
64+
argv = [
2765
sys.executable,
28-
"-m",
29-
"datalab_kernel.kernel",
66+
"-c",
67+
"from datalab_kernel.startup import run_startup; run_startup(); "
68+
"import xeus_python; xeus_python.main()",
69+
"-f",
70+
"{connection_file}",
71+
]
72+
else:
73+
# Use native xpython executable
74+
argv = [
75+
xpython,
3076
"-f",
3177
"{connection_file}",
32-
],
78+
]
79+
80+
return {
81+
"argv": argv,
3382
"display_name": KERNEL_DISPLAY_NAME,
3483
"language": "python",
3584
"metadata": {
3685
"debugger": True,
3786
},
87+
"env": {
88+
# Ensure our startup runs
89+
"DATALAB_KERNEL_STARTUP": "1",
90+
},
3891
}
3992

4093

@@ -65,6 +118,70 @@ def get_kernel_dir(user: bool = True) -> Path:
65118
return data_dir / KERNEL_NAME
66119

67120

121+
def get_ipython_startup_dir() -> Path:
122+
"""Get the IPython startup directory.
123+
124+
Returns:
125+
Path to IPython startup directory (creates if needed).
126+
"""
127+
# Get IPython directory
128+
ipython_dir = Path.home() / ".ipython" / "profile_default" / "startup"
129+
ipython_dir.mkdir(parents=True, exist_ok=True)
130+
return ipython_dir
131+
132+
133+
def install_startup_script() -> Path:
134+
"""Install the DataLab startup script for IPython.
135+
136+
This script will be executed automatically when xeus-python starts
137+
with IPython mode enabled.
138+
139+
Returns:
140+
Path to installed startup script.
141+
"""
142+
startup_dir = get_ipython_startup_dir()
143+
startup_file = startup_dir / "00-datalab-kernel.py"
144+
145+
# Only install if DATALAB_KERNEL_STARTUP env var is set
146+
# This prevents the startup from running in regular IPython sessions
147+
script_content = '''\
148+
# DataLab Kernel Startup Script
149+
# Auto-generated by datalab-kernel - do not edit manually
150+
151+
import os
152+
153+
# Only run startup if we're in a DataLab kernel
154+
if os.environ.get("DATALAB_KERNEL_STARTUP") == "1":
155+
try:
156+
from datalab_kernel.startup import run_startup
157+
run_startup()
158+
except ImportError:
159+
pass # DataLab kernel not installed
160+
'''
161+
162+
with open(startup_file, "w", encoding="utf-8") as f:
163+
f.write(script_content)
164+
165+
print(f"Installed DataLab startup script to: {startup_file}")
166+
return startup_file
167+
168+
169+
def remove_startup_script() -> bool:
170+
"""Remove the DataLab startup script from IPython.
171+
172+
Returns:
173+
True if script was found and removed.
174+
"""
175+
startup_dir = get_ipython_startup_dir()
176+
startup_file = startup_dir / "00-datalab-kernel.py"
177+
178+
if startup_file.exists():
179+
startup_file.unlink()
180+
print(f"Removed DataLab startup script from: {startup_file}")
181+
return True
182+
return False
183+
184+
68185
def install_kernel(user: bool = True, prefix: str | None = None) -> Path:
69186
"""Install the DataLab kernel.
70187
@@ -94,7 +211,11 @@ def install_kernel(user: bool = True, prefix: str | None = None) -> Path:
94211
for logo_file in logo_dir.glob("logo-*.png"):
95212
shutil.copy(logo_file, kernel_dir)
96213

214+
# Install IPython startup script for namespace injection
215+
install_startup_script()
216+
97217
print(f"Installed DataLab kernel to: {kernel_dir}")
218+
print("Note: Uses xeus-python backend for improved performance and debugging")
98219
return kernel_dir
99220

100221

@@ -116,6 +237,8 @@ def uninstall_kernel(user: bool = True, prefix: str | None = None) -> bool:
116237
if kernel_dir.exists():
117238
shutil.rmtree(kernel_dir)
118239
print(f"Uninstalled DataLab kernel from: {kernel_dir}")
240+
# Also remove startup script
241+
remove_startup_script()
119242
return True
120243
print(f"DataLab kernel not found at: {kernel_dir}")
121244
return False

0 commit comments

Comments
 (0)