66==================================
77
88This 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
1113from __future__ import annotations
1214
1315import argparse
1416import json
17+ import os
1518import shutil
1619import sys
1720from pathlib import Path
1821
1922KERNEL_NAME = "datalab-kernel"
2023KERNEL_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
2352def 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+
68185def 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