Skip to content

Python

Python is widely used for scientific programming, also on the DelftBlue cluster. To run your Python scripts you need python (or a specific version of python), most likely some Python-packages, and in many cases a Python Virtual Environment. To ease the maintenance of these parts, several solutions (tools) have been created and can be used on DelftBlue. In this documentation you will find instructions on how to use the solutions:

  1. System installed Python: Python version (old) provided by operating system
  2. Python module: fairly new Python version with many Python packages as modules
  3. Conda: complete solution for all Python versions, packages and virtual environment
  4. uv: fast, lockfile-based management of Python versions, packages and virtual environments

Depending on your choice you could end up installing packages locally. If that is the case please, read the instructions in the following warning:

Installing packages

Please be aware: package managers such as uv, pip or conda are known to install a lot of tiny files locally. This is important for several reasons:

  1. These local installations can occupy a lot of space and default to your /home directory, which has a 30 GB quota. Where possible, point their caches somewhere else: pip honours PIP_CACHE_DIR, conda has pkgs_dirs / CONDA_PKGS_DIRS, and uv has UV_CACHE_DIR (see uv storage and disk usage). Keep the environments themselves on /home or your project drive — /scratch is periodically purged.
  2. These local installation might rely on the /tmp folder as an intermediate storage for unpacking/compiling. Please be aware that the collectively used /tmp might get overfilled! More info here.
  3. /home and /scratch rely on the parallel file system BeeGFS. While this file system provides high speed for truly parallel jobs (many processes reading/writing from/to one big file), it might struggle with processes generating a lot of tiny files. As such, installing packages via pip or conda might take noticeably longer than you would expect. This is normal, and only manifests itself once, during the installation. Once installed, accessing these packages should be very fast.
  4. Only the login nodes have a direct connection to the internet, and compute/GPU nodes are firewalled off from it. If you load the GPU software stack (module load 2026 gpu) on a login node, you get the same Python build and GPU-aware libraries (CUDA headers, etc.) that the GPU compute nodes use, even though login nodes have no GPU card themselves. This means you can fully pip install GPU-enabled packages (e.g. torch, cupy) on a login node, and the resulting virtual environment will run unmodified on the GPU nodes — see Python module below. You only need an actual interactive GPU job if a package's installer insists on probing a real GPU device during installation (rare).

System installed Python

This Python version is mainly installed for system related tasks and should not be used for scientific programming. You can however use this version without any setup or configuration and as such it might come handy as a quick tool to do some small scripting. The program python is located in /usr/bin/python and as of this writing (27/11/2025) is version 3.6.8. You can use packages installed in the system:

python -m pip list

And install packages locally in your home directory (~/.local/lib/python3.6/site-packages) with this command (using numpy as an example):

python -m pip install --user numpy

Note: the --user will install the package in your home directory and not in the system location

You can create a virtual environment using the venv package:

mkdir test_project
cd test_project
python -m venv env
source env/bin/activate

This will create the directory test_project/env with a link to the system Python version. After activating with env/bin/activate the environment variable will be set so you will use the local versions of python and pip. All installations of packages will also be done only locally in the test_project/env directory.

In this virtual environment you can also install your packages:

pip install pip --upgrade
pip install diplib

Python module

A recent python version is available in every DelftBlue software stack.

In these instructions the latest stack 2026 is used. If a newer stack is available please replace 2026 with the newer version.

Since the 2026 stack, you also need to specify which architecture flavour to load: cpu for code that will run on regular compute nodes, or gpu for code (or packages) targeting the GPU nodes:

module load 2026 cpu
module load python

or

module load 2026 gpu
module load python

This choice can be made on any node, including a login node, even though login nodes have no GPU card themselves — loading the gpu flavour there gives you the same Python build and GPU-aware libraries that the GPU compute nodes use, which is what makes it possible to build a GPU-ready virtual environment straight from a login node (see Using pip in a virtual environment below).

Then we have:

[<netid>@login01 ~]$ python
Python 3.13.12 (main, ...) [GCC ...] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>>

From this you can see that Python version 3.13.12 is available in stack 2026

Python packages

For every new version of Python a large set of packages is build and also made available with the module system. Every package-module starts with py- and the name of the package. Which py- packages are available (and which version) can differ between the cpu and gpu flavour of the stack — for example, GPU-accelerated packages such as py-cupy are typically only found under 2026 gpu. Below is an example of the available packages in stack 2026:

[<netid>@login01 ~]$ module load 2026 gpu
[<netid>@login01 ~]$ module avail py-

-------------- /apps/2026/gpu/lmod/linux-almalinux9-x86_64/Core ---------------
   py-aiohappyeyeballs/2.6.1               py-idna/3.10                            py-pyproject-hooks/1.2.0
   py-aiohttp/3.12.15                      py-importlib-metadata/8.7.0             py-pyproject-metadata/0.11.0
   py-aiosignal/1.4.0                      py-jinja2/3.1.6                         py-python-dateutil/2.8.2
   py-attrs/25.3.0                         py-joblib/1.5.3                         py-pythran/0.18.1
   py-beniget/0.4.2.post1                  py-kiwisolver/1.4.8                     py-pyyaml/6.0.3
   py-build/1.2.2                          py-llvmlite/0.45.1                      py-reportlab/4.4.9
   py-calver/2025.10.20                    py-locket/1.0.0                         py-requests/2.32.5
   py-certifi/2026.1.4                     py-mako/1.3.10                          py-rst2pdf/0.103.1
   py-cffi/2.0.0                           py-markupsafe/3.0.2                     py-scikit-build-core/0.12.2
   py-charset-normalizer/3.4.4             py-matplotlib/3.10.8                    py-scikit-learn/1.8.0
   py-click/8.3.1                          py-meson-python/0.19.0                  py-scipy/1.17.1
   py-cloudpickle/3.1.2                    py-mpmath/1.3.0                         py-setuptools-scm/8.2.1
   py-coherent-licensed/0.5.2              py-msgpack/1.0.3                        py-setuptools/79.0.1
   py-contourpy/1.3.3                      py-multidict/6.7.0                      py-shapely/2.1.2
   py-cppy/1.3.1                           py-networkx/3.5                         py-six/1.17.0
   py-cupy/14.0.0a1                        py-numba/0.62.1                         py-smartypants/2.0.2
   py-cycler/0.12.1                        py-numpy/2.3.5                          py-sortedcontainers/2.4.0
   py-cython/3.0.12                        py-numpy/2.4.3                    (D)   py-sympy/1.14.0
   py-cython/3.2.4                   (D)   py-packaging/26.0                       py-tblib/1.6.0
   py-dask/2025.7.0                        py-pandas/3.0.1                         py-threadpoolctl/3.6.0
   py-distributed/2025.7.0                 py-partd/1.4.2                          py-toolz/0.12.0
   py-docutils/0.22.4                      py-pathspec/0.12.1                      py-torch-geometric/2.5.3
   py-expandvars/1.1.2                     py-pillow/12.1.1                        py-torch/2.10.0
   py-fastrlock/0.8.3                      py-pip/25.1.1                           py-tornado/6.5.2
   py-filelock/3.19.1                      py-pluggy/1.6.0                         py-tqdm/4.67.1
   py-flit-core/3.12.0                     py-ply/3.11                             py-trove-classifiers/2025.9.11.17
   py-fonttools/4.39.4                     py-poetry-core/2.2.0                    py-typing-extensions/4.15.0
   py-frozenlist/1.8.0                     py-propcache/0.4.1                      py-urllib3/2.6.3
   py-fsspec/2025.9.0                      py-psutil/7.2.2                         py-versioneer/0.28
   py-fypp/3.2                             py-pybind11/3.0.1                       py-versioneer/0.29                (D)
   py-gast/0.6.0                           py-pycparser/2.23                       py-wheel/0.45.1
   py-geopandas/1.1.3                      py-pygments/2.19.2                      py-yarl/1.22.0
   py-hatch-fancy-pypi-readme/25.1.0       py-pyogrio/0.11.1                       py-zict/3.0.0
   py-hatch-vcs/0.5.0                      py-pyparsing/3.3.2                      py-zipp/3.23.0
   py-hatchling/1.27.0                     py-pyproj/3.7.2

Note that the packages listed here are for the gpu flavour of the stack — this is also where GPU-accelerated packages such as py-cupy and py-torch show up. The cpu flavour (module avail py- after module load 2026 cpu) has an overlapping but not identical list.

For example, if we need numpy, scipy, and matplotlib, we need to load the following modules:

module load py-numpy
module load py-scipy
module load py-matplotlib

Then we have:

[<netid>@login01 ~]$ python
Python 3.13.12 (main, ...) [GCC ...] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> import numpy
>>> import scipy
>>> import matplotlib
>>>

Using pip in a virtual environment

If the package you need is not available as a module, you can use pip to install this package only inside a virtual environment.

Similar to the explanation above with the system installed Python, you can also create a virtual environment with the Python-module:

mkdir test_project
cd test_project
python -m venv env
source env/bin/activate
pip install diplib

Installing GPU-enabled packages

Load the gpu flavour of the stack before creating the virtual environment, and you can pip install GPU-enabled packages directly, from a login node:

module load 2026 gpu python
mkdir gpu_project
cd gpu_project
python -m venv env
source env/bin/activate
pip install torch --index-url https://download.pytorch.org/whl/cu130

Loading gpu (instead of cpu) up front is what makes this work from a login node without an actual GPU card present, and the resulting env will run unmodified on the GPU compute nodes — no separate build/install step on a GPU node needed.

About the CUDA version

This pip-installed PyTorch bundles its own CUDA 13.0 runtime as pip dependencies (nvidia-cuda-runtime-cu13, etc.) — it does not need, and should not be combined with, a module load cuda. If you separately need to compile a custom CUDA extension with nvcc, note that the module system's cuda modules currently only go up to cuda/12.9, slightly behind this wheel's CUDA 13.0 runtime. In that case, use the cu126 index instead (https://download.pytorch.org/whl/cu126), which stays closer to what the module system's cuda toolkit versions can offer.

Warning

Mixing module-loaded packages and your locally installed packages might lead to dependency conflicts!

Avoiding version clash

For example, the standard py-numpy package is at the moment of writing version 2.4.3 (stack 2026). You can update this locally with the following command:

(env) [<netid>@login03 ~]$ pip install --upgrade numpy

And this will make a more recent (2.5.0) version available:

[<netid>@login03 ~]$ pip list
Package       Version
------------- -------
...
numpy         2.5.0
...

However, if you then load the standard py-scipy package (e.g., version 1.17.1, stack 2026), it will re-enable the default numpy version:

(env)[<netid>@login03 ~]$ pip list
Package       Version
------------- -------
...
numpy         2.4.3
scipy         1.17.1
...

Funfact: watch what happens when you unload this py-scipy module...

In this case, you might want to install your own updated scipy version locally as well to avoid the version conflict:

(env)pip install --upgrade scipy

And then we have both more recent versions of numpy and scipy installed locally:

(env) [<netid>@login03 ~]$ pip list
Package       Version
------------- -------
...
numpy         2.5.0
scipy         1.18.0
...

Matching interpreter paths on GPU nodes

Create the virtual environment with the same architecture flavour of the stack you intend to run it with. If you plan to run on GPU nodes, load module load 2026 gpu python (as in Installing GPU-enabled packages above) before running python -m venv, even while you're still on a login node. This way env/bin/python and env/bin/python3 already point to the same interpreter that the GPU nodes resolve to, so the environment works unmodified once activated there — no manual fix-up needed.

Conda

A similar result can be achieved by using the miniconda package manager. See here for instructions how to install it.

Local conda environment on login nodes

Create your own conda environment:

conda create -y -p [my-conda-env]

Activate the environment:

conda activate [my-conda-env]

You should see the environment activated, which is indicated by the prefix to the login prompt:

(my-conda-env) [<netid>@login01 ~]$

Now you can install your own conda packages:

conda install [your-package-name]

To de-activate your environment, simply issue the following:

conda deactivate

To remove your environment, issue the following:

conda env remove --name [your-package-name]

To list all environments, issue the following:

conda env list

Warning

Even though conda activate [my-conda-env] works on the login node prompt, it might fail on the worker nodes.

The problem is that conda init adds the path of the currently active conda installation to your .bashrc, which is probably not what you want, as the conda might change depending on whether you are in compute or gpu mode. And it might not actually work on worker nodes.

It may be best to avoid conda init altogether and directly call conda.sh that comes with the installed version. That can be done with the following command, which calls conda.sh directly by extracting the long string from conda info):

unset CONDA_SHLVL
source "$(conda info --base)/etc/profile.d/conda.sh"
Why unset is necessary before conda init

If there are multiple versions/instances of conda on the system, the PATH may end up being resolved to the wrong python executable when running conda activate. To avoid this, unsetting the conda is required before activating your environment.

More details can be found here.

After running this command, conda activate works on all nodes.

Warning

miniconda3 might conflict with the vendor-preinstalled git!!! To avoid this conflict, load the new openssh and git modules from the DelftBlue software stack!

module load openssh
module load git

uv

Setting up virtual environments and installing packages by hand with venv and pip is tedious to keep in sync, and Conda's environment resolution can be slow.

uv is a newer tool that addresses this. It is written in Rust and is fast, it manages the virtual environment for you, and its lockfile-based workflow makes environments easy to reproduce and share.

Installing uv

uv is not (yet) available as a module, so install it once in your home directory:

curl -LsSf https://astral.sh/uv/install.sh | sh

The installer puts the uv binary in ~/.local/bin, which is already on your PATH on DelftBlue. Start a new shell afterwards so it is picked up.

Creating a project

uv works per project. uv init sets the project's Python version; if that version is not installed, uv downloads a standalone build of it on first use (this needs internet, so stay on a login node):

uv init test_project --python=3.13
cd test_project

Add packages with uv add. This resolves the environment, creates .venv on first use, and records everything in pyproject.toml and uv.lock:

uv add diplib

Run commands in the environment without activating it:

uv run python my_script.py

For interactive work you can still activate the environment the usual way — just keep using uv add rather than pip install, so pyproject.toml and uv.lock stay in sync:

source .venv/bin/activate

Running a uv environment in a Slurm job

uv add and uv sync need internet and must run on a login node, not inside a compute job. In the job script, activate the environment (or use uv run):

source /path/to/test_project/.venv/bin/activate

By default uv uses its own downloaded Python, so the interpreter-path matching described under Matching interpreter paths on GPU nodes does not apply. If you specifically want the stack's Python, load it first and point uv at it:

module load 2026 cpu python      # or: 2026 gpu python
uv venv --python "$(which python)"

uv storage and disk usage

uv keeps a package cache in ~/.cache/uv/ and any downloaded Python builds in ~/.local/share/uv/python/. Both live in /home and count against your 30 GB quota; the project's .venv sits in the project directory.

If /home gets tight, redirect the cache (it is rebuildable) and, if needed, the downloaded Pythons:

export UV_CACHE_DIR=/scratch/${USER}/.cache/uv
export UV_PYTHON_INSTALL_DIR=/scratch/${USER}/.local/uv/python

uv cache clean empties the cache. Keep your projects and their .venv on /home or your project drive — /scratch is periodically purged and must not be used for anything you want to keep.

git with uv

uv is built to work with git. After cloning a repository that was set up with uv, the only step needed is:

uv sync

This installs the recorded Python version together with all packages from the lockfile.

You must commit pyproject.toml, uv.lock and .python-version for this to work. Do not commit .venv (uv init adds it to .gitignore for you).

FAQ

Python only prints STDOUT in a file after the job is finished

Example situation: I am running a Python code that contains print statements via Slurm. Normally when I run the Python code directly via python program.py the print statements appear in the terminal. When I run my program via Slurm, the print statements are written either in the output file specified in the submission script, or in the slurm-XXX.out. However, sometimes the contents of the slurm-XXX.out only appear after the job is actually finished, and not during the run, as I would expect.

This behaviour has to do with the buffering of the python's print command. You can either use the flush=True statement in the print command to flush the buffer to force the output to be printed:

print("hey", flush=True)

Or, if you know what you are doing, you can run python unbuffered:

python -u program.py

More details can be found here.