Jupyterlab and an R env

I am trying to get a persistent jupyterhub/lab up and running on nixos. I have made progress, but stuck on two items. First, is it possible in the approach I am using to add jupyterlab extensions declaratively? I saw that its possible if I build specific shells and do my coding only inside those purpose built shells, but I would rather not take that approach. Second, while I got a python env up and running with some basic data science packages to try out, I can’t get an R environment to work. Console won’t connect to the kernel, even after multiple attempts and trying to build the env and the argv different ways, including finding and using the full path to the R bin. Pasting my code below, if anyone has pointers who may have tried this. Thanks!

{ config, lib, pkgs, ... }:
{

services.jupyterhub = {
enable = true;
jupyterhubEnv = pkgs.python311.withPackages (p: with p; [
    jupyterhub
    jupyterhub-systemdspawner
    pip
    ipython
    jupyter
    notebook
    ipykernel
  ]);
jupyterlabEnv = pkgs.python311.withPackages (p: with p; [
    jupyterhub
    jupyterlab
    pip
    ipython
    jupyter
    notebook
    ipykernel
  ]);
kernels = {
  python311 = let
    env = (pkgs.python311.withPackages (python311Packages: with python311Packages; [
      ipykernel
      pandas
      scikit-learn
      numpy
      seaborn
      matplotlib
      scipy
    ]));
  in {
    displayName = "Python 3 for ML";
    argv = [
      "${env.interpreter}"
      "-m"
      "ipykernel_launcher"
      "-f"
      "{connection_file}"
    ];
    language = "python";
    logo32 = "${env.sitePackages}/ipykernel/resources/logo-32x32.png";
    logo64 = "${env.sitePackages}/ipykernel/resources/logo-64x64.png";
  };
  R = let
    env = (pkgs.rWrapper.override {
      packages = with pkgs.rPackages; [
        IRkernel
        tidyverse
        caret
        randomForest
        tidymodels
        purrr
        shiny
        data_table
        jsonlite
      ];
    });
  in {
    displayName = "R for ML";
    argv = [
      "/nix/store/pqynpqccbr41zz3pg844qiq2h87mxhwx-R-4.3.2-wrapper/bin/R"
      "--slave"
      "-e"
      "IRkernel::main()"
      "--args"
      "{connection_file}"
    ];
    language = "R";
    logo32 = "${env.sitePackages}/IRKernel/resources/logo-32x32.png";
    logo64 = "${env.sitePackages}/IRkernel/resources/logo-64x64.png";
  };
};
};
}

Im pretty sure absolute paths to the nix store dont work. Maybe you should use ${pkgs.R}/bin/R instead of "/nix/store/pqynpqccbr41zz3pg844qiq2h87mxhwx-R-4.3.2-wrapper/bin/R"

I was able to get the R environment to load by using {env}/bin/R. So this is partially solved. One remaining challenge is loading non-python packages in the underlying jupyterhub/lab environment. Jupyterlab-git needs regular git installed, which it obviously is on the base system, but the jupyterhub/lab environment for some reason can’t see it. I must need to load it into the hub/lab environment. They are built like this:

jupyterhubEnv = pkgs.python311.withPackages (p: with p; [
    jupyterhub
    jupyterhub-systemdspawner
    pip
    ...

It appears you can only load python packages into the underlying environment. Is there a way to load non python packages, such as git?

Hi, did you figure this out? I am trying to do it using pkgs.buildEnv, and then putting python3.withPackages into its paths attr as well as git, like:

jupyterlabEnv = (
  pkgs.buildEnv {
    name = "jupyterlab-env";
    paths = with pkgs; [
      (pkgs.python3.withPackages (
        p: with p; [
          jupyterhub
          jupyterlab
          python-lsp-server
          jupyterlab-git
        ]
      ))
      git
    ];
  }
);

but jupyter still complains that git is missing;
image

What you could try is

jupyterlabEnv = (pkgs.python3.withPackages (p: with p; [
  jupyterlab
])).overrideAttrs (prev: {
  extraPathsFrom = prev.extraPathsFrom ++ [
    pkgs.git
  ];
});

Didn’t test.

extraPathsFrom does not seem to have the semantics I assumed, while using symlinkJoin I can build a derivation that has “both” the jupyter environment and git in the derivation’s bin folder:

pkgs.symlinkJoin { name = "myjupyterlab"; paths = [ pkgs.git (pkgs.python3.withPackages(p: with p; [ jupyterlab ])) ]; }

I cannot really test with jupyterhub service though as I always get server error 500 even with ‘dummy’ authenticator.

That doesn’t work either. I have a feeling this is a path issue with python3Packages.jupyterlab-git, as it has git in propagatedBuildInputs but it can’t find it.

Mar 08 12:32:25 itxserve jupyterhub-singleuser[592512]: [W 2025-03-08 12:32:25.562 ServerApp.jupyterlab_git] Fail to execute ['git', '--version']
Mar 08 12:32:25 itxserve jupyterhub-singleuser[592512]:     Traceback (most recent call last):
Mar 08 12:32:25 itxserve jupyterhub-singleuser[592512]:       File "/nix/store/52x0mssdlyw4diwr0bf6y3ki9h7n76lq-python3-3.12.8-env/lib/python3.12/site-packages/jupyterlab_git/git.py", line 189, in execute
Mar 08 12:32:25 itxserve jupyterhub-singleuser[592512]:         code, output, error = await current_loop.run_in_executor(
Mar 08 12:32:25 itxserve jupyterhub-singleuser[592512]:                               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
Mar 08 12:32:25 itxserve jupyterhub-singleuser[592512]:       File "/nix/store/qrc496n6fsqp4p5m5h8wmw5d5jwyw5mr-python3-3.12.8/lib/python3.12/concurrent/futures/thread.py", line 59, in run
Mar 08 12:32:25 itxserve jupyterhub-singleuser[592512]:         result = self.fn(*self.args, **self.kwargs)
Mar 08 12:32:25 itxserve jupyterhub-singleuser[592512]:                  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
Mar 08 12:32:25 itxserve jupyterhub-singleuser[592512]:       File "/nix/store/52x0mssdlyw4diwr0bf6y3ki9h7n76lq-python3-3.12.8-env/lib/python3.12/site-packages/jupyterlab_git/git.py", line 150, in call_subprocess
Mar 08 12:32:25 itxserve jupyterhub-singleuser[592512]:         process = subprocess.Popen(
Mar 08 12:32:25 itxserve jupyterhub-singleuser[592512]:                   ^^^^^^^^^^^^^^^^^
Mar 08 12:32:25 itxserve jupyterhub-singleuser[592512]:       File "/nix/store/qrc496n6fsqp4p5m5h8wmw5d5jwyw5mr-python3-3.12.8/lib/python3.12/subprocess.py", line 1026, in __init__
Mar 08 12:32:25 itxserve jupyterhub-singleuser[592512]:         self._execute_child(args, executable, preexec_fn, close_fds,
Mar 08 12:32:25 itxserve jupyterhub-singleuser[592512]:       File "/nix/store/qrc496n6fsqp4p5m5h8wmw5d5jwyw5mr-python3-3.12.8/lib/python3.12/subprocess.py", line 1955, in _execute_child
Mar 08 12:32:25 itxserve jupyterhub-singleuser[592512]:         raise child_exception_type(errno_num, err_msg, err_filename)
Mar 08 12:32:25 itxserve jupyterhub-singleuser[592512]:     FileNotFoundError: [Errno 2] No such file or directory: 'git'

jupyterlab-git is being called from inside the python3.withPackages env, but I need it to be kinda in the next level up in the regular buildEnv so it can see git

[philip@itxserve:~/repos/nixos]$ ls /nix/store/zzj3whdrah2xdb1f37aan8a7qdhglkgx-python3-3.12.8-env/bin
2to3               hg-nbdiff      ipython3         jupyterhub-singleuser  jupyter-server        nbshow      python
2to3-3.12          hg-nbdiffweb   jlpm             jupyter-kernel         jupyter-troubleshoot  normalizer  python3
alembic            hg-nbmerge     jsonpointer      jupyter-kernelspec     jupyter-trust         pybabel     python3.12
certipy            hg-nbmergeweb  jsonschema       jupyter-lab            mako-render           pydoc       python3.12-config
chardetect         httpx          jupyter          jupyter-labextension   nbdiff                pydoc3      python3-config
git-nbdiffdriver   idle           jupyter-dejavu   jupyter-labhub         nbdiff-web            pydoc3.12   python-config
git-nbdifftool     idle3          jupyter-events   jupyter-migrate        nbdime                pygmentize  send2trash
git-nbmergedriver  idle3.12       jupyter-execute  jupyter-nbconvert      nbmerge               pyjson5     wsdump
git-nbmergetool    ipython        jupyterhub       jupyter-run            nbmerge-web           pylsp

Solution:

jupyterlabEnv = pkgs.python3.withPackages (
  p: with p; [
    (jupyterhub.overridePythonAttrs (previousAttrs: {
      dependencies = previousAttrs.dependencies ++ [ pkgs.git ];
    }))
    jupyterlab
    python-lsp-server
    jupyterlab-git
  ]
);
1 Like

Just wanted to provide an example of a complete working R kernel configuration, as the one above is incomplete:

        R = let
          env = (pkgs.rWrapper.override {
            packages = with pkgs.rPackages; [
              IRkernel
              tidyverse
              purrr
            ];
          });
        in {
          displayName = "R Example";
          argv = [
            "${env}/bin/R"
            "--slave"
            "-e"
            "IRkernel::main()"
            "--args"
            "{connection_file}"
          ];
          language = "R";
          logo64 = "${pkgs.rPackages.IRkernel}/library/IRkernel/kernelspec/logo-64x64.png";
        };

I also couldn’t login with my local account’s username and password with the default PAM authentication for some reason. As in my case it is exclusively for local use I set the authentication to dummy based on the jupyterhub docs Authenticators — JupyterHub documentation for authenticators, and the host to localhost to be safe even tough I don’t have port 8000 open on my firewall:

host = "127.0.0.1"; # default is 0.0.0.0
authentication = "jupyterhub.auth.DummyAuthenticator";