Quick summary
Summarize this blog with AI
You install a package, see a successful message, return to your notebook, and still get ModuleNotFoundError. Running the installer again says Requirement already satisfied. Both messages can be true: the package is installed, but it is installed for a different Python interpreter than the one running your notebook.
This is rarely a Pandas, NumPy, or Jupyter bug. It is usually an identity problem. Your terminal, editor, Jupyter server, and notebook kernel can each point to a different Python installation. The reliable fix is to identify the interpreter behind the failing notebook, install into that interpreter's environment, select the matching kernel, and restart it.
The five pieces people accidentally treat as one
Python data work becomes much easier once you separate five concepts that often look like a single application.
1. The project folder
Your project folder contains notebooks, scripts, data, and configuration files. Its location does not determine where third-party packages are installed. Saving analysis.ipynb beside a .venv folder also does not automatically make the notebook use that environment.
2. The Python interpreter
The interpreter is the executable that runs Python code. A computer can have several: an operating-system Python, a python.org installation, Homebrew Python, a conda installation, and one interpreter inside every virtual environment. Each can see a different collection of packages.
3. The virtual environment
A virtual environment is an isolated Python installation with its own package directory. Activation changes the current shell's PATH so commands such as python and pip resolve to that environment. Activation affects that terminal session; it does not reach backward into an already-running notebook kernel.
4. The Jupyter server
The server provides the notebook interface, manages files, and starts kernels. It may run from one Python environment while offering kernels from several others. That separation is useful: you can install Jupyter once and register multiple project environments as kernels.
5. The notebook kernel
The kernel is the live process that executes cells and keeps variables in memory. For a normal Python notebook, it is an IPython kernel backed by one specific interpreter. The selected kernel—not the folder containing the notebook and not necessarily the Python that launched the Jupyter server—decides which packages an import can find.
The core rule is simple: install the package into the environment used by the selected kernel.
Diagnose the mismatch before changing anything
Start in the notebook that fails. Run this cell:
import os
import sys
print('Python executable:', sys.executable)
print('Python version:', sys.version)
print('Working directory:', os.getcwd())
sys.executable is the most important line. It tells you which Python process is executing the notebook. A project environment should usually produce a path ending in something like .venv/bin/python on macOS or Linux, or .venv\Scripts\python.exe on Windows.
Next, ask the current kernel's package installer about the missing distribution:
%pip --version
%pip show pandas
IPython's %pip magic runs pip in the current kernel. That makes it safer in a notebook than !pip, which launches whatever executable the temporary shell finds first. Replace pandas with the distribution you intended to install.
If you need to inspect Python's import locations, run:
import importlib.util
import sys
print(importlib.util.find_spec('pandas'))
for path in sys.path:
print(path)
sys.path is the ordered list of locations Python searches for importable modules. A package can exist elsewhere on disk and still be invisible because its installation directory is not on this list. Do not immediately append a random site-packages directory to sys.path; that hides the environment mismatch and can combine incompatible dependencies.
How to read the results
%pip showsays the package is missing: it is not installed for the current kernel. Install it with%pip install pandas, then restart the kernel.- The terminal finds the package but
%pip showdoes not: the terminal and notebook use different interpreters. %pip showfinds it butfind_specreturnsNone: check whether the distribution name and import name differ, and check for a broken installation.find_specpoints into your project: a local file or folder may be shadowing the real package.- The path and package are correct but an imported package behaves like an old version: restart the kernel to clear the live process.
The fastest safe fix inside a notebook
If you intentionally want the package in the environment used by the current kernel, run:
%pip install pandas
Then use the notebook interface to restart the kernel and run the import again:
import pandas as pd
print(pd.__version__)
print(pd.__file__)
The final two lines confirm both the loaded version and its location. This is a good immediate repair, but a repeatable project should also define its environment outside the notebook so another person can recreate it.
Why python -m pip is more reliable than plain pip
In a terminal, pip install pandas asks the shell to find a program named pip. That program may belong to a different Python than the python command you use later. python -m pip install pandas instead tells a particular Python interpreter to run its pip module. Installation and execution are therefore tied to the same interpreter.
Verify the pairing before installing:
python -c "import sys; print(sys.executable)"
python -m pip --version
python -m pip show pandas
On Windows, the py launcher is useful before an environment is active, but after activation, use python -m pip so the command follows the active environment. If you do not want to activate an environment, call its interpreter by its full path.
A clean setup on macOS or Linux
From the project directory, create one environment, install the notebook tools and dependencies into it, and register a clearly named kernel:
python3 -m venv .venv
source .venv/bin/activate
python -m pip install --upgrade pip
python -m pip install jupyterlab ipykernel pandas
python -m ipykernel install --user --name analytics --display-name 'Python (analytics)'
python -m jupyter lab
Open the notebook and select Python (analytics) from the kernel menu. The --name value is Jupyter's internal identifier; --display-name is what appears in the interface. Use unique, descriptive names when you register multiple environments.
Activation is convenient, not magical. The standard library allows you to use an environment without activating it. For example, .venv/bin/python -m pip install pandas targets that environment explicitly.
A clean setup on Windows
In PowerShell or Command Prompt, create the environment:
py -m venv .venv
Activate it in PowerShell:
.venv\Scripts\Activate.ps1
Or activate it in Command Prompt:
.venv\Scripts\activate.bat
Then install and register the kernel:
python -m pip install --upgrade pip
python -m pip install jupyterlab ipykernel pandas
python -m ipykernel install --user --name analytics --display-name 'Python (analytics)'
python -m jupyter lab
If activation is unavailable, target the environment directly:
.venv\Scripts\python.exe -m pip install jupyterlab ipykernel pandas
.venv\Scripts\python.exe -m ipykernel install --user --name analytics --display-name 'Python (analytics)'
.venv\Scripts\python.exe -m jupyter lab
In VS Code, use the notebook's kernel selector rather than assuming the editor's general Python interpreter selection changed an existing notebook session. After selecting the environment, verify it inside a cell with sys.executable.
Conda environments follow the same rule
A conda environment is still an environment with a particular Python and package set. Create and register one deliberately:
conda create --name analytics python=3.12 pandas jupyterlab ipykernel
conda activate analytics
python -m ipykernel install --user --name analytics --display-name 'Python (analytics)'
python -m jupyter lab
Prefer conda install for packages you want conda to manage. If a package is only available through pip, install pip in the environment and run python -m pip after activating it. Avoid alternating between unrelated global pip and conda commands; always check sys.executable and python -m pip --version.
Why restarting the kernel matters
A kernel is a long-running process. Imported modules are cached in sys.modules, objects created from old code stay in memory, and compiled libraries may already be loaded. A brand-new pure Python package can sometimes import immediately after installation, but upgrades, dependency changes, and previously failed imports are less predictable.
Restarting creates a clean process with the selected interpreter's current packages. After an install or upgrade, restart the kernel, run cells from the top, and verify the version and file path. Restarting the browser tab or Jupyter server alone is not the same as restarting the notebook kernel.
Common fixes that create a bigger problem
- Running
!pip installrepeatedly: the shell's pip may not belong to the kernel. Use%pipin IPython or the environment'spython -m pipin a terminal. - Installing everything globally: it may solve one import while creating version conflicts for another project. Use one environment per project.
- Using
--userto bypass an environment: a user-site installation may still be invisible to the kernel and makes the active package source harder to reason about. - Manually pasting a package directory into
sys.path: this can mix packages built for different Python versions. Fix the interpreter or kernel selection instead. - Deleting Python installations at random: first identify every relevant executable. Removing an installation can leave stale launchers and kernelspecs behind.
- Trusting a generic kernel label: several environments can appear as “Python 3.” Register descriptive display names and verify with
sys.executable. - Ignoring local name collisions: a file named
pandas.py,requests.py, ornumpy.pycan shadow the installed package. Rename it and remove its generated__pycache__after confirming the collision.
A deterministic troubleshooting checklist
- Reproduce the failed import in the affected notebook.
- Print
sys.executable,sys.version, andos.getcwd(). - Run
%pip --versionand%pip show package-name. - Compare those paths with
python -c "import sys; print(sys.executable)"andpython -m pip --versionin the terminal you used to install. - If they differ, select or register the intended kernel. Do not alter
sys.path. - Install through
%pipor through the exact environment interpreter with-m pip. - Restart the kernel and run the notebook from the top.
- Confirm the import with the package's
__version__and__file__. - Check for a local file or folder that has the same name as the import.
- Record dependencies in a requirements file,
pyproject.toml, or conda environment file so the fix is reproducible.
FAQ
Why does pip say “Requirement already satisfied” when Jupyter cannot import the package?
That message only describes the Python environment associated with the pip command you ran. It does not prove that the selected notebook kernel uses the same environment. Compare the location shown by python -m pip --version with the notebook's sys.executable, then use %pip show inside the notebook.
Should I install packages from inside Jupyter?
%pip install is appropriate for an immediate installation into the current IPython kernel. For a maintained project, also define dependencies in a file and build the environment from a terminal or automated setup. A notebook cell that installs packages on every run makes execution slower and can silently change versions.
What is the difference between a Python interpreter and a Jupyter kernel?
The interpreter executes Python. A Jupyter kernel is a persistent process that wraps an interpreter and communicates with the notebook interface. The kernel retains variables and imports between cells. Its kernelspec tells Jupyter which executable to start.
Why does the import work in a terminal but not in my notebook?
The terminal command and notebook are probably using different interpreters, or the notebook's working directory contains a file that shadows the package. Print sys.executable and os.getcwd() in both contexts instead of assuming they match.
Do I need to install Jupyter in every virtual environment?
No. You can run the Jupyter server from one environment and install ipykernel in each project environment, then register each environment as a kernel. Installing Jupyter inside every project is also valid and can be simpler for beginners, but it duplicates the notebook tooling.
Why are the installation name and import name sometimes different?
Python packaging distinguishes a distribution installed by pip from the module imported by code. Examples include installing scikit-learn but importing sklearn, and installing Pillow but importing PIL. Check the package's official documentation before concluding that the installation failed.
How do I remove a stale kernel entry?
Run jupyter kernelspec list to inspect registered kernels. After verifying the exact internal name, remove an obsolete entry with jupyter kernelspec uninstall old-name. Removing a kernelspec does not necessarily delete the underlying environment, and deleting an environment does not always remove its kernelspec.
Related reading
- Python Packaging User Guide: pip and virtual environments
- IPython: installing kernels for different environments
- IPython: the
%pipmagic - Jupyter Client: kernels and kernelspecs
- Conda: managing environments
When Jupyter cannot see an installed package, stop reinstalling blindly. Identify the notebook's interpreter, target that interpreter's environment, select its kernel, and restart. Once those four steps agree, the import error usually becomes a straightforward package issue instead of an environment mystery.