10
10
import threading
11
11
import time
12
12
import traceback
13
+ import venv
13
14
14
15
from time import sleep
15
16
from jupyter_client import BlockingKernelClient
20
21
import gpt_code_ui .kernel_program .utils as utils
21
22
import gpt_code_ui .kernel_program .config as config
22
23
23
- USE_SEPARATE_VENV = False
24
-
25
24
# Set up globals
26
25
messaging = None
27
26
logger = config .get_logger ()
@@ -170,9 +169,58 @@ def flush_kernel_msgs(kc, tries=1, timeout=0.2):
170
169
logger .debug (f"{ e } [{ type (e )} " )
171
170
172
171
172
+ def create_venv (venv_dir : pathlib .Path , install_default_packages : bool ) -> pathlib .Path :
173
+ venv_bindir = venv_dir / 'bin'
174
+ venv_python_executable = venv_bindir / os .path .basename (sys .executable )
175
+
176
+ if not os .path .isdir (venv_dir ):
177
+ # create virtual env inside venv_dir directory
178
+ venv .create (venv_dir , system_site_packages = True , with_pip = True , upgrade_deps = True )
179
+
180
+ if install_default_packages :
181
+ # install wheel because some packages do not like being installed without
182
+ subprocess .run ([venv_python_executable , '-m' , 'pip' , 'install' , 'wheel>=0.41,<1.0' ])
183
+ # install all default packages into the venv
184
+ default_packages = [
185
+ "ipykernel>=6,<7" ,
186
+ "numpy>=1.24,<1.25" ,
187
+ "dateparser>=1.1,<1.2" ,
188
+ "pandas>=1.5,<1.6" ,
189
+ "geopandas>=0.13,<0.14" ,
190
+ "tabulate>=0.9.0<1.0" ,
191
+ "PyPDF2>=3.0,<3.1" ,
192
+ "pdfminer>=20191125,<20191200" ,
193
+ "pdfplumber>=0.9,<0.10" ,
194
+ "matplotlib>=3.7,<3.8" ,
195
+ "openpyxl>=3.1.2,<4" ,
196
+ ]
197
+ subprocess .run ([venv_python_executable , '-m' , 'pip' , 'install' ] + default_packages )
198
+
199
+ # get base env library path as we need this to refer to this form a derived venv
200
+ site_packages = subprocess .check_output ([venv_python_executable , '-c' , 'import sysconfig; print(sysconfig.get_paths()["purelib"])' ])
201
+ site_packages = site_packages .decode ('utf-8' ).split ('\n ' )[0 ]
202
+
203
+ return pathlib .Path (site_packages )
204
+
205
+
206
+ def create_derived_venv (base_venv : pathlib .Path , venv_dir : pathlib .Path ):
207
+ site_packages_base = create_venv (base_venv , install_default_packages = True )
208
+ site_packages_derived = create_venv (venv_dir , install_default_packages = False )
209
+
210
+ # create a link from derived venv into the base venv, see https://stackoverflow.com/a/75545634
211
+ with open (site_packages_derived / '_base_packages.pth' , 'w' ) as pth :
212
+ pth .write (f'{ site_packages_base } \n ' )
213
+
214
+ venv_bindir = venv_dir / 'bin'
215
+ venv_python_executable = venv_bindir / os .path .basename (sys .executable )
216
+
217
+ return venv_bindir , venv_python_executable
218
+
219
+
173
220
def start_kernel (id : str ):
174
221
cwd = pathlib .Path (os .getcwd ())
175
222
kernel_dir = cwd / f'kernel.{ id } '
223
+ base_dir = cwd / 'kernel.base'
176
224
177
225
# Cleanup potential leftovers
178
226
shutil .rmtree (kernel_dir , ignore_errors = True )
@@ -182,33 +230,9 @@ def start_kernel(id: str):
182
230
kernel_connection_file = kernel_dir / "kernel_connection_file.json"
183
231
launch_kernel_script_path = pathlib .Path (__file__ ).parent .resolve () / "launch_kernel.py"
184
232
185
- if not USE_SEPARATE_VENV :
186
- kernel_python_executable = sys .executable # TODO: here we could also pick up an already existing env by simply selecting the corresponding Python binary
187
- else :
188
- kernel_venv = kernel_dir / 'venv'
189
- kernel_venv_bindir = kernel_venv / 'bin'
190
- kernel_python_executable = kernel_venv_bindir / os .path .basename (sys .executable )
191
- kernel_env ['PATH' ] = str (kernel_venv_bindir ) + os .pathsep + kernel_env ['PATH' ]
192
-
193
- # create virtual env inside kernel_venv directory
194
- subprocess .run ([sys .executable , '-m' , 'venv' , kernel_venv , '--upgrade-deps' , '--system-site-packages' ])
195
- # install wheel because some packages do not like being installed without
196
- subprocess .run ([kernel_python_executable , '-m' , 'pip' , 'install' , 'wheel>=0.41,<1.0' ])
197
- # install all default packages into the venv
198
- default_packages = [
199
- "ipykernel>=6,<7" ,
200
- "numpy>=1.24,<1.25" ,
201
- "dateparser>=1.1,<1.2" ,
202
- "pandas>=1.5,<1.6" ,
203
- "geopandas>=0.13,<0.14" ,
204
- "tabulate>=0.9.0<1.0" ,
205
- "PyPDF2>=3.0,<3.1" ,
206
- "pdfminer>=20191125,<20191200" ,
207
- "pdfplumber>=0.9,<0.10" ,
208
- "matplotlib>=3.7,<3.8" ,
209
- "openpyxl>=3.1.2,<4" ,
210
- ]
211
- subprocess .run ([kernel_python_executable , '-m' , 'pip' , 'install' ] + default_packages )
233
+ kernel_venv_dir = kernel_dir / 'venv'
234
+ kernel_venv_bindir , kernel_python_executable = create_derived_venv (base_dir , kernel_venv_dir )
235
+ kernel_env ['PATH' ] = str (kernel_venv_bindir ) + os .pathsep + kernel_env ['PATH' ]
212
236
213
237
# start the kernel using the virtual env python executable
214
238
kernel_process = subprocess .Popen (
0 commit comments