Here’s a really quick recipe that I use when I’m writing scratch code. If you have a Jupyter notebook running and you want to install or upgrade a package for that environment, you can run the following in a cell:

import sys

!$sys.executable -m pip install <package>

For example, the following would upgrade seaborn to the latest version in the current environment:

import sys

!$sys.executable -m pip install --upgrade seaborn

Why does it work? Well, you can call pip with the python executable by using the -m flag:

python -m pip install ...

And in a Python session, the sys.executable attribute is a string with the full path to the executable for the current environment, e.g.:

sys.executable

# Exected result like...
# /Users/myname/anaconda3/envs/myenv/bin/python

Additionally, we use ! to escape shell commands in a notebook and $ to insert Python variables from the current session into that shell command.

After you run the command, you might need to restart the notebook for the new package to be available.

Finally, a quick word of warning: you should usually avoid this pattern! Whenever possible, you want your Python code to be in a reproducible environment. Use something like Poetry for that, or at least save dependencies in requirements.txt.

Still, notebooks can be useful for scratch code and sometimes reproducibility is not a major concern. In those scenarios, you want to get your environment working as quickly as possible. For this kind of use case, try this trick!