4.1. Setting up a venv-sandboxed Python kernel

This notebooks explains how to set up a new venv-sandboxed Python kernel and make it available in your JupyterLab environment, assuming that you are running this notebook in a standard linux-based environment and a regular (non-root) using running commands in a bash terminal.

This is meant to provide helpful hints to get you over the hump, not as a comprehensive tutorial. This may not work for your environment!

You might also want to consult the official IPython kernel installation documentation for a more general explanation.

4.1.1. Creating and installing a new venv-sandboxed Python kernel

From a bash terminal, cd to your home directory, and create a new hidden directory in which you will put all your virtual environments.

user@host:~$ mkdir .virtualenvs

Then, create a new venv (the venv in this example is named “foo”, because of course it is).

user@host:~$ python3 -m venv .virtualenvs/foo

Activate the new venv. Once activated, the venv name is displayed in parentheses at the front of your command prompt, as shown below.

user@host:~$ source .virtualenvs/foo/bin/activate
(foo) user:host:~$

Use pip to install ipykernel inside your new venv.

(foo) user@host:~$ pip install ipykernel

Install your new ipykernel into your user kernel library, and give it a nice name that will make sense when you see the new kernel listed in the JupyterLab interface.

(foo) user@host:~$ python -m ipykernel install --user --name foo --display-name "Python 3 (venv:foo)"

Deactivate the venv in your terminal when you are done.

(foo) user@host:~$ deactivate

When you open a new Launcher tab in JupyterLab, you should see the new venv-sandboxed Python kernel listed next to the default system Python kernel.

To display a list to confirm which jupyter kernels are currently installed in your environment, you can run the following command from a terminal.

user@host:~$ jupyter kernelspec list

To uninstall the “foo” kernel, run the following command.

user@host:~$ jupyter kernelspec uninstall foo

This only uninstalls the jupyter kernel. It does not remove the venv containing the kernelspec from your system. To delete a venv, just delete the directory it is contained in.

user@host:~$ rm -rf .virtualenvs/foo

4.1.2. Installing Python packages

There are multiple ways to install Python packages into your new venv, such that your venv-sandboxed Python kernel will pick these up when you run import commands in your code.

The easiest way is to use built-in %pip IPython magic commands from a JupyterLab notebook (or console) that is running your venv-sandboxed kernelspec.

For example, to install the dev branch of the ws3 package in the new “foo” venv you could run this line of code from inside the kernel.

[1]:
%pip install -U git+https://github.com/UBC-FRESH/ws3@dev
Collecting git+https://github.com/UBC-FRESH/ws3@dev
  Cloning https://github.com/UBC-FRESH/ws3 (to revision dev) to /tmp/pip-req-build-l2gxo0fg
  Running command git clone --filter=blob:none --quiet https://github.com/UBC-FRESH/ws3 /tmp/pip-req-build-l2gxo0fg
  Resolved https://github.com/UBC-FRESH/ws3 to commit 5c23c01504c5a9fbe1e0d73b79468b90e5e2536e
  Installing build dependencies ... done
  Getting requirements to build wheel ... done
  Preparing metadata (pyproject.toml) ... done
Requirement already satisfied: dill in /home/gep/projects/ws3/.venv/lib/python3.12/site-packages (from ws3==1.0.1.post1) (0.4.0)
Requirement already satisfied: fiona in /home/gep/projects/ws3/.venv/lib/python3.12/site-packages (from ws3==1.0.1.post1) (1.10.1)
Requirement already satisfied: libcbm in /home/gep/projects/ws3/.venv/lib/python3.12/site-packages (from ws3==1.0.1.post1) (2.8.1)
Requirement already satisfied: matplotlib in /home/gep/projects/ws3/.venv/lib/python3.12/site-packages (from ws3==1.0.1.post1) (3.10.5)
Requirement already satisfied: numba in /home/gep/projects/ws3/.venv/lib/python3.12/site-packages (from ws3==1.0.1.post1) (0.61.2)
Requirement already satisfied: numpy>=1.21 in /home/gep/projects/ws3/.venv/lib/python3.12/site-packages (from ws3==1.0.1.post1) (2.2.6)
Requirement already satisfied: pandas>=1.3 in /home/gep/projects/ws3/.venv/lib/python3.12/site-packages (from ws3==1.0.1.post1) (2.3.1)
Requirement already satisfied: profilehooks in /home/gep/projects/ws3/.venv/lib/python3.12/site-packages (from ws3==1.0.1.post1) (1.13.0)
Requirement already satisfied: pulp in /home/gep/projects/ws3/.venv/lib/python3.12/site-packages (from ws3==1.0.1.post1) (3.2.2)
Requirement already satisfied: rasterio in /home/gep/projects/ws3/.venv/lib/python3.12/site-packages (from ws3==1.0.1.post1) (1.4.3)
Requirement already satisfied: scipy>=1.7 in /home/gep/projects/ws3/.venv/lib/python3.12/site-packages (from ws3==1.0.1.post1) (1.16.1)
Requirement already satisfied: python-dateutil>=2.8.2 in /home/gep/projects/ws3/.venv/lib/python3.12/site-packages (from pandas>=1.3->ws3==1.0.1.post1) (2.9.0.post0)
Requirement already satisfied: pytz>=2020.1 in /home/gep/projects/ws3/.venv/lib/python3.12/site-packages (from pandas>=1.3->ws3==1.0.1.post1) (2025.2)
Requirement already satisfied: tzdata>=2022.7 in /home/gep/projects/ws3/.venv/lib/python3.12/site-packages (from pandas>=1.3->ws3==1.0.1.post1) (2025.2)
Requirement already satisfied: six>=1.5 in /home/gep/projects/ws3/.venv/lib/python3.12/site-packages (from python-dateutil>=2.8.2->pandas>=1.3->ws3==1.0.1.post1) (1.17.0)
Requirement already satisfied: attrs>=19.2.0 in /home/gep/projects/ws3/.venv/lib/python3.12/site-packages (from fiona->ws3==1.0.1.post1) (25.3.0)
Requirement already satisfied: certifi in /home/gep/projects/ws3/.venv/lib/python3.12/site-packages (from fiona->ws3==1.0.1.post1) (2025.8.3)
Requirement already satisfied: click~=8.0 in /home/gep/projects/ws3/.venv/lib/python3.12/site-packages (from fiona->ws3==1.0.1.post1) (8.2.1)
Requirement already satisfied: click-plugins>=1.0 in /home/gep/projects/ws3/.venv/lib/python3.12/site-packages (from fiona->ws3==1.0.1.post1) (1.1.1.2)
Requirement already satisfied: cligj>=0.5 in /home/gep/projects/ws3/.venv/lib/python3.12/site-packages (from fiona->ws3==1.0.1.post1) (0.7.2)
Requirement already satisfied: numexpr>=2.8.7 in /home/gep/projects/ws3/.venv/lib/python3.12/site-packages (from libcbm->ws3==1.0.1.post1) (2.11.0)
Requirement already satisfied: pyyaml in /home/gep/projects/ws3/.venv/lib/python3.12/site-packages (from libcbm->ws3==1.0.1.post1) (6.0.2)
Requirement already satisfied: mock in /home/gep/projects/ws3/.venv/lib/python3.12/site-packages (from libcbm->ws3==1.0.1.post1) (5.2.0)
Requirement already satisfied: openpyxl in /home/gep/projects/ws3/.venv/lib/python3.12/site-packages (from libcbm->ws3==1.0.1.post1) (3.1.5)
Requirement already satisfied: contourpy>=1.0.1 in /home/gep/projects/ws3/.venv/lib/python3.12/site-packages (from matplotlib->ws3==1.0.1.post1) (1.3.3)
Requirement already satisfied: cycler>=0.10 in /home/gep/projects/ws3/.venv/lib/python3.12/site-packages (from matplotlib->ws3==1.0.1.post1) (0.12.1)
Requirement already satisfied: fonttools>=4.22.0 in /home/gep/projects/ws3/.venv/lib/python3.12/site-packages (from matplotlib->ws3==1.0.1.post1) (4.59.0)
Requirement already satisfied: kiwisolver>=1.3.1 in /home/gep/projects/ws3/.venv/lib/python3.12/site-packages (from matplotlib->ws3==1.0.1.post1) (1.4.8)
Requirement already satisfied: packaging>=20.0 in /home/gep/projects/ws3/.venv/lib/python3.12/site-packages (from matplotlib->ws3==1.0.1.post1) (25.0)
Requirement already satisfied: pillow>=8 in /home/gep/projects/ws3/.venv/lib/python3.12/site-packages (from matplotlib->ws3==1.0.1.post1) (11.3.0)
Requirement already satisfied: pyparsing>=2.3.1 in /home/gep/projects/ws3/.venv/lib/python3.12/site-packages (from matplotlib->ws3==1.0.1.post1) (3.2.3)
Requirement already satisfied: llvmlite<0.45,>=0.44.0dev0 in /home/gep/projects/ws3/.venv/lib/python3.12/site-packages (from numba->ws3==1.0.1.post1) (0.44.0)
Requirement already satisfied: et-xmlfile in /home/gep/projects/ws3/.venv/lib/python3.12/site-packages (from openpyxl->libcbm->ws3==1.0.1.post1) (2.0.0)
Requirement already satisfied: affine in /home/gep/projects/ws3/.venv/lib/python3.12/site-packages (from rasterio->ws3==1.0.1.post1) (2.4.0)
Building wheels for collected packages: ws3
  Building wheel for ws3 (pyproject.toml) ... done
  Created wheel for ws3: filename=ws3-1.0.1.post1-py3-none-any.whl size=68862 sha256=cb2ddcef266d270a5e8882073129b1bafdd07c9749038093605532fd7a95e81c
  Stored in directory: /tmp/pip-ephem-wheel-cache-5068uxut/wheels/bc/c0/27/54eff522cdcea94d53d5fd804ea8e244cc4c9d364c99149628
Successfully built ws3
Installing collected packages: ws3
  Attempting uninstall: ws3
    Found existing installation: ws3 1.1.0.dev0
    Uninstalling ws3-1.1.0.dev0:
      Successfully uninstalled ws3-1.1.0.dev0
Successfully installed ws3-1.0.1.post1
Note: you may need to restart the kernel to use updated packages.

You can test to make sure that your kernel is now picking up the venv-sandboxed version of the package by importing the package and inspecting the value of the package __path__ attribute.

[3]:
import ws3
ws3.__path__, ws3.__version__
[3]:
(['/home/gep/projects/ws3/.venv/lib/python3.12/site-packages/ws3'],
 '1.0.1-post1')

You can also use the “%pip” magic command to uninstall packages from your venv.

For example to uninstall the ws3 package we installed earlier in the “foo” venv, run the following command from inside the kernel. Note the “-y” flag, which skips asking for user confirmation before uninstalling stuff (else the kernel will hang forever waiting for your response, which you cannot provide from inside a Jupyter notebook or console environment).

[4]:
%pip uninstall -y ws3
Found existing installation: ws3 1.0.1.post1
Uninstalling ws3-1.0.1.post1:
  Successfully uninstalled ws3-1.0.1.post1
Note: you may need to restart the kernel to use updated packages.

Note also that it is possible to install an “editable” version of a Python package inside your venv-sandboxed kernel by cloning a GitHub repo for the Python package you want to use into your project environment and running the “%pip” magic command with the “-e” flag and point to the local directory containing the cloned copy of the package code.

For example, we can clone the dev branch of the ws3 GitHub repo into our project directory like this.

[6]:
!git clone https://github.com/UBC-FRESH/ws3
fatal: destination path 'ws3' already exists and is not an empty directory.

Then we can configure our venv-sandboxed kernel environment to use that local copy of the code when Python imports ws3 by running the following magic command (assuming this notebook is running the venv kernel).

[7]:
%pip install -e ./ws3
Obtaining file:///home/gep/projects/ws3/examples/ws3
  Installing build dependencies ... done
  Checking if build backend supports build_editable ... done
  Getting requirements to build editable ... done
  Installing backend dependencies ... done
  Preparing editable metadata (pyproject.toml) ... done
Requirement already satisfied: dill in /home/gep/projects/ws3/.venv/lib/python3.12/site-packages (from ws3==1.0.1.post1) (0.4.0)
Requirement already satisfied: fiona in /home/gep/projects/ws3/.venv/lib/python3.12/site-packages (from ws3==1.0.1.post1) (1.10.1)
Requirement already satisfied: libcbm in /home/gep/projects/ws3/.venv/lib/python3.12/site-packages (from ws3==1.0.1.post1) (2.8.1)
Requirement already satisfied: matplotlib in /home/gep/projects/ws3/.venv/lib/python3.12/site-packages (from ws3==1.0.1.post1) (3.10.5)
Requirement already satisfied: numba in /home/gep/projects/ws3/.venv/lib/python3.12/site-packages (from ws3==1.0.1.post1) (0.61.2)
Requirement already satisfied: numpy>=1.21 in /home/gep/projects/ws3/.venv/lib/python3.12/site-packages (from ws3==1.0.1.post1) (2.2.6)
Requirement already satisfied: pandas>=1.3 in /home/gep/projects/ws3/.venv/lib/python3.12/site-packages (from ws3==1.0.1.post1) (2.3.1)
Requirement already satisfied: profilehooks in /home/gep/projects/ws3/.venv/lib/python3.12/site-packages (from ws3==1.0.1.post1) (1.13.0)
Requirement already satisfied: pulp in /home/gep/projects/ws3/.venv/lib/python3.12/site-packages (from ws3==1.0.1.post1) (3.2.2)
Requirement already satisfied: rasterio in /home/gep/projects/ws3/.venv/lib/python3.12/site-packages (from ws3==1.0.1.post1) (1.4.3)
Requirement already satisfied: scipy>=1.7 in /home/gep/projects/ws3/.venv/lib/python3.12/site-packages (from ws3==1.0.1.post1) (1.16.1)
Requirement already satisfied: python-dateutil>=2.8.2 in /home/gep/projects/ws3/.venv/lib/python3.12/site-packages (from pandas>=1.3->ws3==1.0.1.post1) (2.9.0.post0)
Requirement already satisfied: pytz>=2020.1 in /home/gep/projects/ws3/.venv/lib/python3.12/site-packages (from pandas>=1.3->ws3==1.0.1.post1) (2025.2)
Requirement already satisfied: tzdata>=2022.7 in /home/gep/projects/ws3/.venv/lib/python3.12/site-packages (from pandas>=1.3->ws3==1.0.1.post1) (2025.2)
Requirement already satisfied: six>=1.5 in /home/gep/projects/ws3/.venv/lib/python3.12/site-packages (from python-dateutil>=2.8.2->pandas>=1.3->ws3==1.0.1.post1) (1.17.0)
Requirement already satisfied: attrs>=19.2.0 in /home/gep/projects/ws3/.venv/lib/python3.12/site-packages (from fiona->ws3==1.0.1.post1) (25.3.0)
Requirement already satisfied: certifi in /home/gep/projects/ws3/.venv/lib/python3.12/site-packages (from fiona->ws3==1.0.1.post1) (2025.8.3)
Requirement already satisfied: click~=8.0 in /home/gep/projects/ws3/.venv/lib/python3.12/site-packages (from fiona->ws3==1.0.1.post1) (8.2.1)
Requirement already satisfied: click-plugins>=1.0 in /home/gep/projects/ws3/.venv/lib/python3.12/site-packages (from fiona->ws3==1.0.1.post1) (1.1.1.2)
Requirement already satisfied: cligj>=0.5 in /home/gep/projects/ws3/.venv/lib/python3.12/site-packages (from fiona->ws3==1.0.1.post1) (0.7.2)
Requirement already satisfied: numexpr>=2.8.7 in /home/gep/projects/ws3/.venv/lib/python3.12/site-packages (from libcbm->ws3==1.0.1.post1) (2.11.0)
Requirement already satisfied: pyyaml in /home/gep/projects/ws3/.venv/lib/python3.12/site-packages (from libcbm->ws3==1.0.1.post1) (6.0.2)
Requirement already satisfied: mock in /home/gep/projects/ws3/.venv/lib/python3.12/site-packages (from libcbm->ws3==1.0.1.post1) (5.2.0)
Requirement already satisfied: openpyxl in /home/gep/projects/ws3/.venv/lib/python3.12/site-packages (from libcbm->ws3==1.0.1.post1) (3.1.5)
Requirement already satisfied: contourpy>=1.0.1 in /home/gep/projects/ws3/.venv/lib/python3.12/site-packages (from matplotlib->ws3==1.0.1.post1) (1.3.3)
Requirement already satisfied: cycler>=0.10 in /home/gep/projects/ws3/.venv/lib/python3.12/site-packages (from matplotlib->ws3==1.0.1.post1) (0.12.1)
Requirement already satisfied: fonttools>=4.22.0 in /home/gep/projects/ws3/.venv/lib/python3.12/site-packages (from matplotlib->ws3==1.0.1.post1) (4.59.0)
Requirement already satisfied: kiwisolver>=1.3.1 in /home/gep/projects/ws3/.venv/lib/python3.12/site-packages (from matplotlib->ws3==1.0.1.post1) (1.4.8)
Requirement already satisfied: packaging>=20.0 in /home/gep/projects/ws3/.venv/lib/python3.12/site-packages (from matplotlib->ws3==1.0.1.post1) (25.0)
Requirement already satisfied: pillow>=8 in /home/gep/projects/ws3/.venv/lib/python3.12/site-packages (from matplotlib->ws3==1.0.1.post1) (11.3.0)
Requirement already satisfied: pyparsing>=2.3.1 in /home/gep/projects/ws3/.venv/lib/python3.12/site-packages (from matplotlib->ws3==1.0.1.post1) (3.2.3)
Requirement already satisfied: llvmlite<0.45,>=0.44.0dev0 in /home/gep/projects/ws3/.venv/lib/python3.12/site-packages (from numba->ws3==1.0.1.post1) (0.44.0)
Requirement already satisfied: et-xmlfile in /home/gep/projects/ws3/.venv/lib/python3.12/site-packages (from openpyxl->libcbm->ws3==1.0.1.post1) (2.0.0)
Requirement already satisfied: affine in /home/gep/projects/ws3/.venv/lib/python3.12/site-packages (from rasterio->ws3==1.0.1.post1) (2.4.0)
Building wheels for collected packages: ws3
  Building editable for ws3 (pyproject.toml) ... done
  Created wheel for ws3: filename=ws3-1.0.1.post1-py3-none-any.whl size=4151 sha256=5364d53efb2ade8d3f483247aa0d497ba2c6c722362da96508d45f7bc5fd9f7a
  Stored in directory: /tmp/pip-ephem-wheel-cache-w4nyts_d/wheels/92/4f/40/0e1d2f2584d079a190b79c34d238033826099ccae6b5868838
Successfully built ws3
Installing collected packages: ws3
Successfully installed ws3-1.0.1.post1
Note: you may need to restart the kernel to use updated packages.

We can check that this is working the way I intended by importing the ws3 package and inspecting its path attribute.

[8]:
import ws3
ws3.__path__, ws3.__version__
[8]:
(['/home/gep/projects/ws3/.venv/lib/python3.12/site-packages/ws3'],
 '1.0.1-post1')

If you want to get really fancy, you can set up your notebook to autoreload the local package anytime you modify the source code by adding these two lines of code to the top of your notebook.

[9]:
%load_ext autoreload
%autoreload 2

This is the basic pattern if you are working on a project that uses ws3 and anticipate needing to tweak the code (at least a little bit) to get it to do exactly what you need it to do for your particular project.