Latest versions via pip: jupyterlab import of matplotlib broken?

When doing a simple ‘import matplotlib’ in JuptyerLab, an “entry point name ‘inline’ duplicated” exception is thrown.

Latest versions of everything installed via pip. See here for more details:

https://www.reddit.com/r/JupyterLab/comments/1d7b4is/matplotlib_import_errors_in_jupyter/

Please can you post the output of pip list, plus what operating system are you using?

Rocky 9.4 x86_64

Package Version


alembic 1.13.1
annotated-types 0.7.0
anyio 4.4.0
argon2-cffi 23.1.0
argon2-cffi-bindings 21.2.0
arrow 1.3.0
ase 3.23.0
asttokens 2.4.1
async-generator 1.10
async-lru 2.0.4
attrs 23.2.0
Babel 2.15.0
beautifulsoup4 4.12.3
bleach 6.1.0
certifi 2024.6.2
certipy 0.1.3
cffi 1.16.0
charset-normalizer 3.3.2
comm 0.2.2
contourpy 1.2.1
cryptography 42.0.8
cycler 0.12.1
debugpy 1.8.1
decorator 5.1.1
defusedxml 0.7.1
exceptiongroup 1.2.1
executing 2.0.1
fastjsonschema 2.19.1
fonttools 4.53.0
fqdn 1.5.1
greenlet 3.0.3
h11 0.14.0
httpcore 1.0.5
httpx 0.27.0
idna 3.7
importlib_metadata 7.1.0
importlib_resources 6.4.0
ipykernel 6.29.4
ipython 8.18.1
ipywidgets 8.1.3
isoduration 20.11.0
jedi 0.19.1
Jinja2 3.1.4
json5 0.9.25
jsonpointer 2.4
jsonschema 4.22.0
jsonschema-specifications 2023.12.1
jupyter_client 8.6.2
jupyter_core 5.7.2
jupyter-events 0.10.0
jupyter-lsp 2.2.5
jupyter_server 2.14.1
jupyter_server_terminals 0.5.3
jupyterhub 5.0.0
jupyterlab 4.2.1
jupyterlab_pygments 0.3.0
jupyterlab_server 2.27.2
jupyterlab_widgets 3.0.11
kiwisolver 1.4.5
Mako 1.3.5
MarkupSafe 2.1.5
matplotlib 3.9.0
matplotlib-inline 0.1.7
mistune 3.0.2
nbclient 0.10.0
nbconvert 7.16.4
nbformat 5.10.4
nest-asyncio 1.6.0
notebook_shim 0.2.4
numpy 1.26.4
oauthlib 3.2.2
overrides 7.7.0
packaging 24.0
pamela 1.1.0
pandocfilters 1.5.1
parso 0.8.4
pexpect 4.9.0
pillow 10.3.0
pip 24.0
platformdirs 4.2.2
prometheus_client 0.20.0
prompt_toolkit 3.0.46
psutil 5.9.8
ptyprocess 0.7.0
pure-eval 0.2.2
pycparser 2.22
pydantic 2.7.3
pydantic_core 2.18.4
Pygments 2.18.0
pyOpenSSL 24.1.0
pyparsing 3.1.2
python-dateutil 2.9.0.post0
python-json-logger 2.0.7
PyYAML 6.0.1
pyzmq 26.0.3
referencing 0.35.1
requests 2.32.3
rfc3339-validator 0.1.4
rfc3986-validator 0.1.1
rpds-py 0.18.1
scipy 1.13.1
Send2Trash 1.8.3
setuptools 53.0.0
six 1.16.0
sniffio 1.3.1
soupsieve 2.5
SQLAlchemy 2.0.30
stack-data 0.6.3
terminado 0.18.1
tinycss2 1.3.0
tomli 2.0.1
tornado 6.4.1
traitlets 5.14.3
types-python-dateutil 2.9.0.20240316
typing_extensions 4.12.1
uri-template 1.3.0
urllib3 2.2.1
wcwidth 0.2.13
webcolors 24.6.0
webencodings 0.5.1
websocket-client 1.8.0
wheel 0.43.0
widgetsnbextension 4.0.11
zipp 3.19.2

Simple script to set up test case is:

mkdir /opt/jupyterhub
python3 -m venv /opt/jupyterhub
/opt/jupyterhub/bin/python3 -m pip install --upgrade pip
/opt/jupyterhub/bin/python3 -m pip install wheel jupyterhub jupyterlab ipywidgets
/opt/jupyterhub/bin/python3 -m pip install matplotlib numpy scipy ase

I cannot reproduce using exactly the same versions of packages that you posted using Ubuntu 24.04 and either system Python 3.11.5 in a venv or Python 3.9.19 in a conda environment. Somehow you have two sets of entry points for matplotlib-inline available at runtime (e.g. filenames entry_points.txt), perhaps there is some path leakage to a system-installed version of matplotlib-inline? Although if I try this I cannot reproduce the problem as only the venv-installed version is read.

It wouldn’t be difficult to allow multiple sets of entry points per package, but I would be hesitant to do so without really understanding and reproducing the situation where this can happen.

that seems not to be the case [and it also used to work before the update]:

[root@hub ~]# locate matplotlib-inline
[root@hub ~]# locate matplotlib_inline
/opt/jupyterhub/lib/python3.9/site-packages/matplotlib_inline
/opt/jupyterhub/lib/python3.9/site-packages/matplotlib_inline-0.1.7.dist-info
/opt/jupyterhub/lib/python3.9/site-packages/matplotlib_inline/init.py
/opt/jupyterhub/lib/python3.9/site-packages/matplotlib_inline/pycache
/opt/jupyterhub/lib/python3.9/site-packages/matplotlib_inline/backend_inline.py
/opt/jupyterhub/lib/python3.9/site-packages/matplotlib_inline/config.py
/opt/jupyterhub/lib/python3.9/site-packages/matplotlib_inline/pycache/init.cpython-39.pyc
/opt/jupyterhub/lib/python3.9/site-packages/matplotlib_inline/pycache/backend_inline.cpython-39.pyc
/opt/jupyterhub/lib/python3.9/site-packages/matplotlib_inline/pycache/config.cpython-39.pyc
/opt/jupyterhub/lib/python3.9/site-packages/matplotlib_inline-0.1.7.dist-info/INSTALLER
/opt/jupyterhub/lib/python3.9/site-packages/matplotlib_inline-0.1.7.dist-info/LICENSE
/opt/jupyterhub/lib/python3.9/site-packages/matplotlib_inline-0.1.7.dist-info/METADATA
/opt/jupyterhub/lib/python3.9/site-packages/matplotlib_inline-0.1.7.dist-info/RECORD
/opt/jupyterhub/lib/python3.9/site-packages/matplotlib_inline-0.1.7.dist-info/WHEEL
/opt/jupyterhub/lib/python3.9/site-packages/matplotlib_inline-0.1.7.dist-info/entry_points.txt
/opt/jupyterhub/lib/python3.9/site-packages/matplotlib_inline-0.1.7.dist-info/top_level.txt
[root@hub ~]# dnf list installed | grep matplot
[root@hub ~]# locate entry_points.txt
/opt/jupyterhub/lib/python3.9/site-packages/Babel-2.15.0.dist-info/entry_points.txt
/opt/jupyterhub/lib/python3.9/site-packages/Mako-1.3.5.dist-info/entry_points.txt
/opt/jupyterhub/lib/python3.9/site-packages/Send2Trash-1.8.3.dist-info/entry_points.txt
/opt/jupyterhub/lib/python3.9/site-packages/alembic-1.13.1.dist-info/entry_points.txt
/opt/jupyterhub/lib/python3.9/site-packages/anyio-4.4.0.dist-info/entry_points.txt
/opt/jupyterhub/lib/python3.9/site-packages/ase-3.23.0.dist-info/entry_points.txt
/opt/jupyterhub/lib/python3.9/site-packages/certipy-0.1.3.dist-info/entry_points.txt
/opt/jupyterhub/lib/python3.9/site-packages/cffi-1.16.0.dist-info/entry_points.txt
/opt/jupyterhub/lib/python3.9/site-packages/charset_normalizer-3.3.2.dist-info/entry_points.txt
/opt/jupyterhub/lib/python3.9/site-packages/fonttools-4.53.0.dist-info/entry_points.txt
/opt/jupyterhub/lib/python3.9/site-packages/httpx-0.27.0.dist-info/entry_points.txt
/opt/jupyterhub/lib/python3.9/site-packages/ipython-8.18.1.dist-info/entry_points.txt
/opt/jupyterhub/lib/python3.9/site-packages/jinja2-3.1.4.dist-info/entry_points.txt
/opt/jupyterhub/lib/python3.9/site-packages/json5-0.9.25.dist-info/entry_points.txt
/opt/jupyterhub/lib/python3.9/site-packages/jsonschema-4.22.0.dist-info/entry_points.txt
/opt/jupyterhub/lib/python3.9/site-packages/jupyter_client-8.6.2.dist-info/entry_points.txt
/opt/jupyterhub/lib/python3.9/site-packages/jupyter_core-5.7.2.dist-info/entry_points.txt
/opt/jupyterhub/lib/python3.9/site-packages/jupyter_events-0.10.0.dist-info/entry_points.txt
/opt/jupyterhub/lib/python3.9/site-packages/jupyter_lsp-2.2.5.dist-info/entry_points.txt
/opt/jupyterhub/lib/python3.9/site-packages/jupyter_server-2.14.1.dist-info/entry_points.txt
/opt/jupyterhub/lib/python3.9/site-packages/jupyterhub-5.0.0.dist-info/entry_points.txt
/opt/jupyterhub/lib/python3.9/site-packages/jupyterlab-4.2.1.dist-info/entry_points.txt
/opt/jupyterhub/lib/python3.9/site-packages/matplotlib_inline-0.1.7.dist-info/entry_points.txt
/opt/jupyterhub/lib/python3.9/site-packages/nbclient-0.10.0.dist-info/entry_points.txt
/opt/jupyterhub/lib/python3.9/site-packages/nbconvert-7.16.4.dist-info/entry_points.txt
/opt/jupyterhub/lib/python3.9/site-packages/nbformat-5.10.4.dist-info/entry_points.txt
/opt/jupyterhub/lib/python3.9/site-packages/numpy-1.26.4.dist-info/entry_points.txt
/opt/jupyterhub/lib/python3.9/site-packages/pip-24.0.dist-info/entry_points.txt
/opt/jupyterhub/lib/python3.9/site-packages/pygments-2.18.0.dist-info/entry_points.txt
/opt/jupyterhub/lib/python3.9/site-packages/setuptools-53.0.0.dist-info/entry_points.txt
/opt/jupyterhub/lib/python3.9/site-packages/websocket_client-1.8.0.dist-info/entry_points.txt
/opt/jupyterhub/lib/python3.9/site-packages/wheel-0.43.0.dist-info/entry_points.txt
/usr/lib/python3.9/site-packages/chardet-4.0.0.dist-info/entry_points.txt
/usr/lib/python3.9/site-packages/conda-4.14.0-py3.9.egg-info/entry_points.txt
/usr/lib/python3.9/site-packages/distro-1.5.0-py3.9.egg-info/entry_points.txt
/usr/lib/python3.9/site-packages/py_cpuinfo-8.0.0-py3.9.egg-info/entry_points.txt
/usr/lib/python3.9/site-packages/setuptools-53.0.0.dist-info/entry_points.txt
/usr/lib/python3.9/site-packages/tqdm-4.65.0.dist-info/entry_points.txt
/usr/lib64/python3.9/site-packages/cffi-1.14.5-py3.9.egg-info/entry_points.txt
/usr/lib64/python3.9/site-packages/conda_package_handling-1.7.3-py3.9.egg-info/entry_points.txt
[root@hub ~]#

the problem only occurs when loading matplotlib in JupyterLab, not from the bash terminal using the venv.

To be even more precise:

[root@hub ~]# find / -type f -name entry_points.txt -exec grep -i inline ‘{}’ ‘;’
inline = matplotlib_inline.backend_inline
[root@hub ~]#

So my conclusion is that the file is read twice somehow when running through a JupyterLab ipython console session?

I can reproduce in a Rocky 9.4 VM. It isn’t actually anything to do with matplotlib, ipython or jupyter.
Simplest reproducer using the pre-prepared virtual environment:

python -c "import importlib.metadata as im; print(im.entry_points().get('matplotlib.backend'))"

or looking at numpy’s entry points instead of matplotlib’s:

python -c "import importlib.metadata as im; print(im.entry_points().get('array_api'))"

In each case there is only one entry points file, but importlib returns two identical items.

I think what is happening is that the virtual env has both a lib directory and a lib64 that is a symlink to lib. Both of these are in the search path for entry points so that same entry point file appears twice under two different paths, even though they refer to the same file. I can only reproduce this if the system Python is 3.9 (newer is fine) and using venv, but I have not exhaustively checked this.

I don’t really know if this is a problem in CPython itself (as importlib is part of the standard library), or in venv, or in Rocky’s setup here. But it doesn’t really matter as matplotlib needs a workaround for this which should be in the 3.9.1 release. Until then I suggest downgrading to matplotlib < 3.9, or better still don’t use the system python with venv but instead use either pyenv or one of the conda/mamba options that allows you to use a more up-to-date python.

Thanx! Indeed, I was able to install python 3.12.1 on Rocky 9.4 [alongside the default 3.9] and setup a venv with that to setup JupyterLab + Hub and matplotlib. Now it all works again. python 3.9 will however be the default for the next 6 years still on RHEL 9 based systems and quite a few of them in HPC I’m afraid.