Issues Using Jupyterlab Extensions with Flox

I’m having some trouble getting widgets (specifically jupyterlab-widgets) to work in my flox environment. I’m able to install them (along with node), but they aren’t recognized by my jupyter environment.

My manifest.toml includes the following specifics.

...
[install]
psycopg.pkg-path = "python312Packages.psycopg"
tqdm.pkg-path = "python312Packages.tqdm"
datasets.pkg-path = "python312Packages.datasets"
ipywidgets.pkg-path = "python312Packages.ipywidgets"
huggingface-hub.pkg-path = "python312Packages.huggingface-hub"
jupyterlab-widgets.pkg-path = "python312Packages.jupyterlab-widgets"
nodejs.pkg-path = "nodejs"
widgetsnbextension.pkg-path = "python312Packages.widgetsnbextension"
pip.pkg-path = "python312Packages.pip"
jupyter.pkg-path = "jupyter"
btop.pkg-path = "btop"
postgresql_15.pkg-path = "postgresql_15"
tmux.pkg-path = "tmux"
ripgrep.pkg-path = "ripgrep"
[hook]
on-activate = '''
   export JUPYTER_PATH=${FLOX_ENV}
   export JUPYTER_CONFIG_PATH=${FLOX_ENV}
'''
...

If I check my paths, I see the following.

ubuntu@ip-172-31-29-88:~/embedding-testing$ jupyter --paths
config:
    /home/ubuntu/.jupyter
    /nix/store/l014xp1qxdl6gim3zc0jv3mpxhbp346s-python3-3.12.4/etc/jupyter
    /usr/local/etc/jupyter
    /etc/jupyter
data:
    /nix/store/2gydn23nxsry8dka3v9wwv0cdn7k3814-jupyter-kernels
    /home/ubuntu/.local/share/jupyter
    /nix/store/l014xp1qxdl6gim3zc0jv3mpxhbp346s-python3-3.12.4/share/jupyter
    /usr/local/share/jupyter
    /usr/share/jupyter
runtime:
    /home/ubuntu/.local/share/jupyter/runtime

but it appears that my extensions are not recognized. Below is the result of running the command jupyter labextension list in a terminal in the notebook.

`sys_prefix` level settings are read-only, using `user` level for migration to `lockedExtensions`
JupyterLab v4.2.4

But when I run that same command directly in my flox shell, I get a different result:

`sys_prefix` level settings are read-only, using `user` level for migration to `lockedExtensions`
JupyterLab v4.2.4
/nix/store/0q0gkxd4gfn8w9cqym8a0xrdpclz37b5-python3-3.12.4-env/share/jupyter/labextensions
        jupyterlab_pygments v0.3.0 enabled OK (python, jupyterlab_pygments)
        @jupyter-notebook/lab-extension v7.2.1 enabled OK

The last thing I was trying was directly specifying the jupter lab config dir to a directory that isn’t read only. That did not seem to make a difference though.

taking a look! initial guess is the init of the kernels may be the issue. some of us have seen issues with telling jupyter to start this python interpreter with this env var when you spin up kernels.

1 Like

i’m not so sure there’s a solution with this particular extension (happy if someone can prove me wrong). this issue Enable labextension for user only · Issue #15574 · jupyterlab/jupyterlab · GitHub makes me think it’s not available yet for read only deployments like Flox and Nix have (and there’s a whole string of issues about it). i’m going to ask a few others to take a look to see if they have any other ideas…

what you can do to work around this in Flox: install the dependency with pip using a venv and don’t rely on Flox for this specific extension. Check out this environment’s hook on FloxHub: FloxHub

(pasting here if you haven’t signed up yet–it’s free!)

  if [[ -d $PYTHON_ENV ]]; then
    echo; echo -n "⚡️ Activating existing venv in $PYTHON_ENV..."
    . $PYTHON_ENV/bin/activate
    echo "done."
  fi

  # If we see a requirements.txt file, install its contents
  # into a virtual environment

  if [[ -f requirements.txt ]]; then
    echo -n "🐍 Processing requirements.txt..."
    [ ! -d $PYTHON_ENV ] && python -m venv $PYTHON_ENV
    . $PYTHON_ENV/bin/activate
    pip3 -qq install -r requirements.txt
    echo "done."
  fi

Just to be super clear, Max when you ran jupyter labextension list in the terminal it didn’t show any paths (the second to last terminal output in your original post)? I’m not a Jupyter user myself but that’s a bit unexpected if Flox is listing more paths but also not finding the plugins.

So I’ve taken the manifest.toml that was provided in the original post and built an environment around it for testing.

When I poke around inside of it, it looks like the widgets are installed (jupyter-widgets specifically):

✦ ❯ ls $FLOX_ENV/share/jupyter/labextensions
@jupyter-notebook  @jupyter-widgets  jupyterlab_pygments

But when you ask jupyter which extensions are installed, it only lists two of them:

✦ ❯ jupyter labextension list
`sys_prefix` level settings are read-only, using `user` level for migration to `lockedExtensions`
JupyterLab v4.2.4
/nix/store/ni927g0pp68wmkbmanw5x5z92d91zgna-python3-3.12.5-env/share/jupyter/labextensions
        jupyterlab_pygments v0.3.0 enabled OK (python, jupyterlab_pygments)
        @jupyter-notebook/lab-extension v7.2.1 enabled OK

The plot thickens

Alright, so here’s the difference:

✦ ❯ readlink "$FLOX_ENV/share/jupyter/labextensions/@jupyter-notebook"
/nix/store/ni927g0pp68wmkbmanw5x5z92d91zgna-python3-3.12.5-env/share/jupyter/labextensions/@jupyter-notebook
✦ ❯ readlink "$FLOX_ENV/share/jupyter/labextensions/jupyterlab_pygments"
/nix/store/ni927g0pp68wmkbmanw5x5z92d91zgna-python3-3.12.5-env/share/jupyter/labextensions/jupyterlab_pygments
✦ ❯ readlink "$FLOX_ENV/share/jupyter/labextensions/@jupyter-widgets"
/nix/store/lcgcbxvdzdvm3dgh4h9j6bgcl7v70imp-python3.12-jupyterlab-widgets-3.0.11/share/jupyter/labextensions/@jupyter-widgets

Those first two packages are coming from the same store path. I’m betting that one of the programs involved has a wrapper script that sets a *PATH variable to that first store path only.

Ah to be more precise–the following output was the result of launching jupyterlab from my flox environment, opening a terminal within that jupyterlab environment, and then running jupyter labextension list

`sys_prefix` level settings are read-only, using `user` level for migration to `lockedExtensions`
JupyterLab v4.2.4

I’ve created a tracking issue where I’m going to put my debugging breadcrumbs instead of blowing up this thread: Some Jupyter notebook extensions aren't found · Issue #2067 · flox/flox · GitHub. Feel free to leave comments in there if you have other details to add (namely, is it just the jupyterlab-widgets extension that isn’t found, or are there others).

Alright, I think I’ve found a solution.

❯ JUPYTER_DATA_DIR="$FLOX_ENV/share/jupyter" jupyter labextension list
`sys_prefix` level settings are read-only, using `user` level for migration to `lockedExtensions`
JupyterLab v4.2.4
/nix/store/ni927g0pp68wmkbmanw5x5z92d91zgna-python3-3.12.5-env/share/jupyter/labextensions
        jupyterlab_pygments v0.3.0 enabled OK (python, jupyterlab_pygments)
        @jupyter-notebook/lab-extension v7.2.1 enabled OK

/Users/zmitchell/src/jupyter-flox/.flox/run/aarch64-darwin.jupyter-flox/share/jupyter/labextensions
        @jupyter-widgets/jupyterlab-manager v5.0.11 enabled OK (python, jupyterlab_widgets)

So, get rid of the other JUPYTER_* variables in your on-activate hook (just in case those mess anything else up), and try

export JUPYTER_DATA_DIR="$FLOX_ENV/share/jupyter"
1 Like

it worked for me! As discussed off line I logged an enhancement to do this variable setting automatically when we detect the right packages installed: Add python activation logic for jupyter labextensions · Issue #2068 · flox/flox · GitHub

This did allow me to see the installed widgets via jupyter labextension list, but permission issues then prevent the jupyter environment from launching:

JUPYTER_DATA_DIR="$FLOX_ENV/share/jupyter" jupyter lab --ip=0.0.0.0
[I 2024-09-08 03:27:21.738 ServerApp] jupyter_lsp | extension was successfully linked.
[I 2024-09-08 03:27:21.741 ServerApp] jupyter_server_terminals | extension was successfully linked.
[I 2024-09-08 03:27:21.744 ServerApp] jupyterlab | extension was successfully linked.
[I 2024-09-08 03:27:21.747 ServerApp] notebook | extension was successfully linked.
[W 2024-09-08 03:27:21.747 ServerApp] notebook_shim | error linking extension: [Errno 13] Permission denied: '/home/ubuntu/embedding-testing/embedding-testing-2/.flox/run/x86_64-linux.embedding-testing-2/share/jupyter/runtime'
    Traceback (most recent call last):
      File "/home/ubuntu/embedding-testing/embedding-testing-2/.flox/run/x86_64-linux.embedding-testing-2/lib/python3.12/site-packages/traitlets/traitlets.py", line 632, in get
        value = obj._trait_values[self.name]
                ~~~~~~~~~~~~~~~~~^^^^^^^^^^^
    KeyError: 'browser_open_file'

    During handling of the above exception, another exception occurred:

    Traceback (most recent call last):
      File "/home/ubuntu/embedding-testing/embedding-testing-2/.flox/run/x86_64-linux.embedding-testing-2/lib/python3.12/site-packages/traitlets/traitlets.py", line 632, in get
        value = obj._trait_values[self.name]
                ~~~~~~~~~~~~~~~~~^^^^^^^^^^^
    KeyError: 'runtime_dir'

    During handling of the above exception, another exception occurred:

    Traceback (most recent call last):
      File "/home/ubuntu/embedding-testing/embedding-testing-2/.flox/run/x86_64-linux.embedding-testing-2/lib/python3.12/site-packages/jupyter_server/extension/manager.py", line 346, in link_extension
        extension.link_all_points(self.serverapp)
      File "/home/ubuntu/embedding-testing/embedding-testing-2/.flox/run/x86_64-linux.embedding-testing-2/lib/python3.12/site-packages/jupyter_server/extension/manager.py", line 228, in link_all_points
        self.link_point(point_name, serverapp)
      File "/home/ubuntu/embedding-testing/embedding-testing-2/.flox/run/x86_64-linux.embedding-testing-2/lib/python3.12/site-packages/jupyter_server/extension/manager.py", line 218, in link_point
        point.link(serverapp)
      File "/home/ubuntu/embedding-testing/embedding-testing-2/.flox/run/x86_64-linux.embedding-testing-2/lib/python3.12/site-packages/jupyter_server/extension/manager.py", line 140, in link
        linker(serverapp)
      File "/home/ubuntu/embedding-testing/embedding-testing-2/.flox/run/x86_64-linux.embedding-testing-2/lib/python3.12/site-packages/notebook_shim/nbserver.py", line 109, in _link_jupyter_server_extension
        members = diff_members(serverapp, nbapp)
                  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
      File "/home/ubuntu/embedding-testing/embedding-testing-2/.flox/run/x86_64-linux.embedding-testing-2/lib/python3.12/site-packages/notebook_shim/nbserver.py", line 62, in diff_members
        m1 = public_members(obj1)
             ^^^^^^^^^^^^^^^^^^^^
      File "/home/ubuntu/embedding-testing/embedding-testing-2/.flox/run/x86_64-linux.embedding-testing-2/lib/python3.12/site-packages/notebook_shim/nbserver.py", line 56, in public_members
        members = inspect.getmembers(obj)
                  ^^^^^^^^^^^^^^^^^^^^^^^
      File "/nix/store/pgb120fb7srbh418v4i2a70aq1w9dawd-python3-3.12.5/lib/python3.12/inspect.py", line 614, in getmembers
        return _getmembers(object, predicate, getattr)
               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
      File "/nix/store/pgb120fb7srbh418v4i2a70aq1w9dawd-python3-3.12.5/lib/python3.12/inspect.py", line 592, in _getmembers
        value = getter(object, key)
                ^^^^^^^^^^^^^^^^^^^
      File "/home/ubuntu/embedding-testing/embedding-testing-2/.flox/run/x86_64-linux.embedding-testing-2/lib/python3.12/site-packages/traitlets/traitlets.py", line 687, in __get__
        return t.cast(G, self.get(obj, cls))  # the G should encode the Optional
                         ^^^^^^^^^^^^^^^^^^
      File "/home/ubuntu/embedding-testing/embedding-testing-2/.flox/run/x86_64-linux.embedding-testing-2/lib/python3.12/site-packages/traitlets/traitlets.py", line 635, in get
        default = obj.trait_defaults(self.name)
                  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
      File "/home/ubuntu/embedding-testing/embedding-testing-2/.flox/run/x86_64-linux.embedding-testing-2/lib/python3.12/site-packages/traitlets/traitlets.py", line 1897, in trait_defaults
        return t.cast(Sentinel, self._get_trait_default_generator(names[0])(self))
                                ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
      File "/home/ubuntu/embedding-testing/embedding-testing-2/.flox/run/x86_64-linux.embedding-testing-2/lib/python3.12/site-packages/traitlets/traitlets.py", line 1241, in __call__
        return self.func(*args, **kwargs)
               ^^^^^^^^^^^^^^^^^^^^^^^^^^
      File "/home/ubuntu/embedding-testing/embedding-testing-2/.flox/run/x86_64-linux.embedding-testing-2/lib/python3.12/site-packages/jupyter_server/serverapp.py", line 1756, in _default_browser_open_file
        return os.path.join(self.runtime_dir, basename)
                            ^^^^^^^^^^^^^^^^
      File "/home/ubuntu/embedding-testing/embedding-testing-2/.flox/run/x86_64-linux.embedding-testing-2/lib/python3.12/site-packages/traitlets/traitlets.py", line 687, in __get__
        return t.cast(G, self.get(obj, cls))  # the G should encode the Optional
                         ^^^^^^^^^^^^^^^^^^
      File "/home/ubuntu/embedding-testing/embedding-testing-2/.flox/run/x86_64-linux.embedding-testing-2/lib/python3.12/site-packages/traitlets/traitlets.py", line 635, in get
        default = obj.trait_defaults(self.name)
                  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
      File "/home/ubuntu/embedding-testing/embedding-testing-2/.flox/run/x86_64-linux.embedding-testing-2/lib/python3.12/site-packages/traitlets/traitlets.py", line 1897, in trait_defaults
        return t.cast(Sentinel, self._get_trait_default_generator(names[0])(self))
                                ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
      File "/home/ubuntu/embedding-testing/embedding-testing-2/.flox/run/x86_64-linux.embedding-testing-2/lib/python3.12/site-packages/jupyter_core/application.py", line 111, in _runtime_dir_default
        ensure_dir_exists(rd, mode=0o700)
      File "/home/ubuntu/embedding-testing/embedding-testing-2/.flox/run/x86_64-linux.embedding-testing-2/lib/python3.12/site-packages/jupyter_core/utils/__init__.py", line 26, in ensure_dir_exists
        Path(path).mkdir(parents=True, mode=mode)
      File "/nix/store/pgb120fb7srbh418v4i2a70aq1w9dawd-python3-3.12.5/lib/python3.12/pathlib.py", line 1311, in mkdir
        os.mkdir(self, mode)
    PermissionError: [Errno 13] Permission denied: '/home/ubuntu/embedding-testing/embedding-testing-2/.flox/run/x86_64-linux.embedding-testing-2/share/jupyter/runtime'
Traceback (most recent call last):
  File "/home/ubuntu/embedding-testing/embedding-testing-2/.flox/run/x86_64-linux.embedding-testing-2/lib/python3.12/site-packages/traitlets/traitlets.py", line 632, in get
    value = obj._trait_values[self.name]
            ~~~~~~~~~~~~~~~~~^^^^^^^^^^^
KeyError: 'runtime_dir'

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "/nix/store/jdaydbij5skwjlijmi350yc8vzlw0zhd-python3.12-jupyterlab-4.2.4/bin/.jupyter-lab-wrapped", line 9, in <module>
    sys.exit(main())
             ^^^^^^
  File "/home/ubuntu/embedding-testing/embedding-testing-2/.flox/run/x86_64-linux.embedding-testing-2/lib/python3.12/site-packages/jupyter_server/extension/application.py", line 616, in launch_instance
    serverapp = cls.initialize_server(argv=args)
                ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/home/ubuntu/embedding-testing/embedding-testing-2/.flox/run/x86_64-linux.embedding-testing-2/lib/python3.12/site-packages/jupyter_server/extension/application.py", line 586, in initialize_server
    serverapp.initialize(
  File "/home/ubuntu/embedding-testing/embedding-testing-2/.flox/run/x86_64-linux.embedding-testing-2/lib/python3.12/site-packages/traitlets/config/application.py", line 118, in inner
    return method(app, *args, **kwargs)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/home/ubuntu/embedding-testing/embedding-testing-2/.flox/run/x86_64-linux.embedding-testing-2/lib/python3.12/site-packages/jupyter_server/serverapp.py", line 2755, in initialize
    self.init_configurables()
  File "/home/ubuntu/embedding-testing/embedding-testing-2/.flox/run/x86_64-linux.embedding-testing-2/lib/python3.12/site-packages/jupyter_server/serverapp.py", line 2065, in init_configurables
    "connection_dir": self.runtime_dir,
                      ^^^^^^^^^^^^^^^^
  File "/home/ubuntu/embedding-testing/embedding-testing-2/.flox/run/x86_64-linux.embedding-testing-2/lib/python3.12/site-packages/traitlets/traitlets.py", line 687, in __get__
    return t.cast(G, self.get(obj, cls))  # the G should encode the Optional
                     ^^^^^^^^^^^^^^^^^^
  File "/home/ubuntu/embedding-testing/embedding-testing-2/.flox/run/x86_64-linux.embedding-testing-2/lib/python3.12/site-packages/traitlets/traitlets.py", line 635, in get
    default = obj.trait_defaults(self.name)
              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/home/ubuntu/embedding-testing/embedding-testing-2/.flox/run/x86_64-linux.embedding-testing-2/lib/python3.12/site-packages/traitlets/traitlets.py", line 1897, in trait_defaults
    return t.cast(Sentinel, self._get_trait_default_generator(names[0])(self))
                            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/home/ubuntu/embedding-testing/embedding-testing-2/.flox/run/x86_64-linux.embedding-testing-2/lib/python3.12/site-packages/jupyter_core/application.py", line 111, in _runtime_dir_default
    ensure_dir_exists(rd, mode=0o700)
  File "/home/ubuntu/embedding-testing/embedding-testing-2/.flox/run/x86_64-linux.embedding-testing-2/lib/python3.12/site-packages/jupyter_core/utils/__init__.py", line 26, in ensure_dir_exists
    Path(path).mkdir(parents=True, mode=mode)
  File "/nix/store/pgb120fb7srbh418v4i2a70aq1w9dawd-python3-3.12.5/lib/python3.12/pathlib.py", line 1311, in mkdir
    os.mkdir(self, mode)
PermissionError: [Errno 13] Permission denied: '/home/ubuntu/embedding-testing/embedding-testing-2/.flox/run/x86_64-linux.embedding-testing-2/share/jupyter/runtime'

We had to fix an issue in nixpkgs where JUPYTER_PATH wasn’t being respected. If you run flox upgrade does it work now? Looking back at your original post, I think you may have to export JUPYTER_PATH="${FLOX_ENV}/share/jupyter" as well (adding the share/jupyter)

2 Likes

This seems to be working! I’m going to continue testing this, but here is my manifest.

version = 1
[install]
psycopg.pkg-path = "python312Packages.psycopg"
tqdm.pkg-path = "python312Packages.tqdm"
datasets.pkg-path = "python312Packages.datasets"
ipywidgets.pkg-path = "python312Packages.ipywidgets"
huggingface-hub.pkg-path = "python312Packages.huggingface-hub"
jupyterlab-widgets.pkg-path = "python312Packages.jupyterlab-widgets"
nodejs.pkg-path = "nodejs"
widgetsnbextension.pkg-path = "python312Packages.widgetsnbextension"
pip.pkg-path = "python312Packages.pip"
jupyter.pkg-path = "jupyter"
btop.pkg-path = "btop"
postgresql_15.pkg-path = "postgresql_15"
tmux.pkg-path = "tmux"
ripgrep.pkg-path = "ripgrep"
pymongo.pkg-path = "python312Packages.pymongo"
[vars]
virtualEnv='./nb-venv/'
[hook]
on-activate = '''
        export PATH=/home/ubuntu/.local/bin:$PATH
        export JUPYTER_PATH="${FLOX_ENV}/share/jupyter"
'''
[profile]
common = """
  alias nb="jupyter lab --ip 0.0.0.0"
  echo; echo "Jupyter environment ready - start notebook with 'nb'."
"""
[options]
systems = ["aarch64-darwin", "aarch64-linux", "x86_64-darwin", "x86_64-linux"]

Amazing! We may add logic to flox activate so that it does the export JUPYTER_PATH="${FLOX_ENV}/share/jupyter" automatically. We’re tracking that in Some Jupyter notebook extensions aren't found · Issue #2067 · flox/flox · GitHub