From 178d7c1b289c80fcaa21921e991089a2d77b916f Mon Sep 17 00:00:00 2001 From: Daniel Hollas Date: Thu, 20 Jun 2024 14:04:25 +0200 Subject: [PATCH] Pin jupyter-notebook version (#469) In aiidalab/aiidalab-qe#640, we were debugging an issue with a stalled pip installation, during which pip started backtracking and looking at old versions of some of the core Jupyter libraries, most notably Jupyter notebook (notebook package). This is definitely not desirable, and if pip was able to finish, it would likely break the container. We've been having discussions in the past about pinning some jupyter-related packages to prevent this scenario from happening. Here we pin at least the notebook package. We definitely don't want users to be able to downgrade the version, and we also don't want them to upgrade it, since we know that v7 will not work as it is a completely different architecture. --- stack/base/Dockerfile | 33 +++++++++++++++++++-------------- tests/test_base.py | 22 ++++++++++++++++++++++ 2 files changed, 41 insertions(+), 14 deletions(-) diff --git a/stack/base/Dockerfile b/stack/base/Dockerfile index 2e7686a6..08e625ab 100644 --- a/stack/base/Dockerfile +++ b/stack/base/Dockerfile @@ -26,30 +26,35 @@ RUN if [ "$TARGETARCH" = "arm64" ]; then \ WORKDIR /opt/ ARG AIIDA_VERSION -# Pin shared requirements in the base environment. -# We pin aiida-core to the exact installed version, -# to prevent accidental upgrade or downgrade, that might + +# Pin certain shared requirements in the base environment +# so that user cannot change their version and accidently break themselves. +# Pin aiida-core to the exact installed version +# to prevent accidental upgrade or downgrade that might # induce DB migration or break shared dependencies of AiiDAlab Apps. RUN echo "aiida-core==${AIIDA_VERSION}" > /opt/requirements.txt -# Install aiida-core and other shared requirements. -RUN mamba install --yes \ - mamba-bash-completion \ - --file /opt/requirements.txt \ - && mamba clean --all -f -y && \ - fix-permissions "${CONDA_DIR}" && \ - fix-permissions "/home/${NB_USER}" +# Pin jupyter-notebook to prevent downgrades or upgrades to v7 +RUN echo "notebook==$(jupyter-notebook --version)" >> /opt/requirements.txt -# Pin shared requirements in the conda base environment. RUN cat /opt/requirements.txt | xargs -I{} conda config --system --add pinned_packages {} -# Upgrade pip to latest -RUN pip install --upgrade --no-cache-dir pip -# Configure pip to use requirements file as constraints file. +# Configure pip to use the same requirements file as constraints file. ENV PIP_CONSTRAINT /opt/requirements.txt # Ensure that pip installs packages to ~/.local by default ENV PIP_USER 1 +# Upgrade pip to latest +RUN mamba update -y pip && mamba clean --all -f -y + +# Install aiida-core and other shared requirements. +RUN mamba install --yes \ + aiida-core==${AIIDA_VERSION} \ + mamba-bash-completion \ + && mamba clean --all -f -y && \ + fix-permissions "${CONDA_DIR}" && \ + fix-permissions "/home/${NB_USER}" + # Enable verdi autocompletion. RUN mkdir -p "${CONDA_DIR}/etc/conda/activate.d" && \ echo 'eval "$(_VERDI_COMPLETE=bash_source verdi)"' >> "${CONDA_DIR}/etc/conda/activate.d/activate_aiida_autocompletion.sh" && \ diff --git a/tests/test_base.py b/tests/test_base.py index 5f60b2ae..9017a41d 100644 --- a/tests/test_base.py +++ b/tests/test_base.py @@ -25,12 +25,34 @@ def test_prevent_installation_of_aiida( ) +@pytest.mark.parametrize("pkg_manager", ["pip", "mamba"]) +def test_prevent_notebook_upgrade(aiidalab_exec, nb_user, pkg_manager): + """jupyter-notebook is pinned to the exact version in the container, + test that both pip and mamba refuse to update to v7 of the notebook.""" + + incompatible_version = "7" + with pytest.raises(Exception): + aiidalab_exec( + f"{pkg_manager} install notebook=={incompatible_version}", + user=nb_user, + ) + + def test_python_version(aiidalab_exec, python_version): info = json.loads(aiidalab_exec("mamba list --json --full-name python"))[0] assert info["name"] == "python" assert parse(info["version"]) == parse(python_version) +def test_pip_version(aiidalab_exec): + """We update pip to latest version when building the image, + test that we're not using and old pip version""" + + info = json.loads(aiidalab_exec("mamba list --json --full-name pip"))[0] + assert info["name"] == "pip" + assert parse(info["version"]) >= parse("24.0") + + def test_create_conda_environment(aiidalab_exec, nb_user): output = aiidalab_exec("conda create -y -n tmp", user=nb_user).strip() assert "conda activate tmp" in output