How to Check the Version of a Python Package With pip

Run python -m pip show <package> and read the Version: line, or use python -m pip list to see every installed package. From Python code, call importlib.metadata.version("package") (Python 3.8+). Always run these with the same interpreter or virtual environment your program uses, because each environment has its own packages.
pip show: one package in detail
python -m pip show requests
Name: requests
Version: 2.32.3
Summary: Python HTTP for Humans.
Home-page: https://requests.readthedocs.io
Author: Kenneth Reitz
Author-email: me@kennethreitz.org
License: Apache-2.0
Location: /home/dev/project/.venv/lib/python3.13/site-packages
Requires: certifi, charset-normalizer, idna, urllib3
Required-by:
Besides the version, the output tells you where the package is installed (Location), which is the fastest way to discover that you are looking at the wrong environment. Requires and Required-by show its dependencies and dependents. You can pass several names at once (pip show requests urllib3), and pip show -f also lists the installed files. See the pip show reference.
If the package is not installed, pip prints a warning and exits with status 1, which is handy in shell scripts:
python -m pip show nosuchpkg; echo "exit=$?"
WARNING: Package(s) not found: nosuchpkg
exit=1
pip list and pip freeze: all packages
pip list prints a table of every distribution in the environment:
python -m pip list
Package Version
------------------ ----------
certifi 2026.10.23
charset-normalizer 3.5.2
idna 3.20
packaging 26.3
pip 26.2.2
requests 2.32.3
urllib3 2.8.0
To find one package, filter the output. pip freeze prints name==version lines in requirements-file format, which are easy to grep:
python -m pip freeze | grep -i requests # Linux / macOS
python -m pip freeze | findstr /i requests # Windows cmd
python -m pip list | Select-String requests # PowerShell
requests==2.32.3
Use -i because names are case-insensitive (PyYAML, Django). Differences worth knowing:
| Command | Output | Notes |
|---|---|---|
pip show NAME | Metadata for one or more packages | Includes location and dependencies |
pip list | Table of all packages | --outdated, --format=json, --not-required |
pip freeze | name==version lines | Hides pip/setuptools by default; packages installed from VCS or local paths appear as URLs |
pip inspect | Full JSON report of the environment | pip 22.2+; meant for tooling |
For scripts, pip list --format=json is more robust than parsing the table:
[{"name": "certifi", "version": "2026.10.23"}, {"name": "charset-normalizer", "version": "3.5.2"}, ...]
Why python -m pip instead of pip
The bare pip command is whichever pip script comes first on your PATH, and it may belong to a different Python than the one that runs your code. On the same machine, the system interpreter and a project virtual environment can report completely different results:
python3 -m pip show requests | head -2 # system Python
.venv/bin/python -m pip show requests | head -2 # project venv
.venv/bin/python -m pip show pandas
Name: requests
Version: 2.34.2
Name: requests
Version: 2.32.3
WARNING: Package(s) not found: pandas
python -m pip guarantees that pip operates on the interpreter you named, which is what the Python Packaging User Guide recommends. On Windows, py -m pip does the same through the launcher (py -3.12 -m pip list targets a specific version). To check which interpreter you are actually running:
python -c "import sys; print(sys.executable)"
Virtual environments and conda
- venv / virtualenv: activate the environment first (
source .venv/bin/activateor.venv\Scripts\activate), or call its interpreter directly (.venv/bin/python -m pip list) without activating. - Tool-managed environments: run the command through the tool so it uses the project environment, for example
poetry run python -m pip show requests,pipenv run pip show requestsoruv pip show requests. - conda: packages installed with
conda installare best queried withconda list numpyin the activated environment.pip listinside a conda environment shows conda-installed packages too, butconda listadditionally shows the build string and channel, and marks packages installed by pip with the channelpypi. - Jupyter: the kernel may run a different interpreter from your terminal. Use
%pip listin a cell; the magic runs pip for the kernel's interpreter.
Checking the version from Python code
importlib.metadata, in the standard library since Python 3.8, reads the same installed metadata that pip uses, without starting a subprocess or importing the package:
from importlib.metadata import version, PackageNotFoundError
print(version("requests"))
try:
version("nosuchpkg")
except PackageNotFoundError as exc:
print("not installed:", exc)
2.32.3
not installed: No package metadata was found for nosuchpkg
On Python 3.7 and older, install the importlib-metadata backport and import from importlib_metadata. Avoid the old pkg_resources.get_distribution() API: it is slow, deprecated, and part of setuptools rather than the standard library.
version() takes the distribution name (what you pip install), not the import name. Most of the time they match, but not always:
version("PyYAML") # '6.0.3'
version("yaml") # PackageNotFoundError: No package metadata was found for yaml
Other common mismatches: scikit-learn / sklearn, Pillow / PIL, beautifulsoup4 / bs4, opencv-python / cv2. Names are normalised, so charset-normalizer and charset_normalizer both work. If you only know the import name, importlib.metadata.packages_distributions() (Python 3.10+) maps it back: packages_distributions()["charset_normalizer"] returns ['charset-normalizer'].
To list everything from code, iterate over distributions():
from importlib.metadata import distributions
for dist in sorted(distributions(), key=lambda d: d.metadata["Name"].lower()):
print(f'{dist.metadata["Name"]}=={dist.version}')
The __version__ attribute and its caveats
Many packages expose a version string on the module:
import requests
print(requests.__version__)
2.32.3
It is a convention, not a standard, so it is unreliable as a general method:
- Some packages do not define it at all;
typing_extensionsandmypyhave no top-level__version__(mypy usesmypy.version.__version__). - Some are removing it. MarkupSafe 3.0 emits
DeprecationWarning: The '__version__' attribute is deprecated and will be removed in MarkupSafe 3.1. Use feature detection, or `importlib.metadata.version("markupsafe")`, instead. - It requires importing the package, which can be slow or have side effects, and the value can drift from the installed metadata in editable or vendored installs.
Prefer importlib.metadata.version() and keep __version__ for quick interactive checks.
Which versions are available?
To see what you could install, ask the index. pip index versions (pip 21.2+) lists available releases and shows what is installed:
python -m pip index versions requests
requests (2.34.2)
Available versions: 2.34.2, 2.34.1, 2.34.0, 2.33.1, 2.33.0, 2.32.5, 2.32.4, 2.32.3, ...
INSTALLED: 2.32.3
LATEST: 2.34.2
The command is marked experimental, and older pip releases print WARNING: pip index is currently an experimental command. It may be removed/changed in a future release without prior warning., so do not build scripts that depend on its exact output. Pre-releases are excluded unless you add --pre. Two alternatives:
python -m pip list --outdated # installed packages with a newer release
python -m pip install requests==0 # trick: the error lists all versions
Package Version Latest Type
-------- ------- ------ -----
requests 2.32.3 2.34.2 wheel
ERROR: Could not find a version that satisfies the requirement requests==0 (from versions: 0.2.0, 0.2.1, ..., 2.34.1, 2.34.2)
The older form pip install requests== (empty version) no longer works in current pip; it fails with ERROR: Invalid requirement. Asking for an impossible version such as ==0 still produces the list.
The project page on PyPI (https://pypi.org/project/requests/#history) shows the same release history with dates.
Comparing versions correctly with packaging
Never compare version strings as strings: "2.10.0" > "2.9.0" is False because the comparison is character by character. The packaging library implements the official version specifier rules (PEP 440), including pre-releases and post-releases:
from importlib.metadata import version
from packaging.version import Version
from packaging.specifiers import SpecifierSet
installed = Version(version("requests"))
print(installed >= Version("2.32"))
print("2.10.0" > "2.9.0", Version("2.10.0") > Version("2.9.0"))
print(Version("1.0rc1") < Version("1.0"), Version("1.0.post1") > Version("1.0"))
print(installed.major, installed.minor, installed.micro)
print(version("requests") in SpecifierSet(">=2.31,<3"))
True
False True
True True
2 32 3
True
A typical use is a guard at program start-up:
import sys
from importlib.metadata import version
from packaging.version import Version
if Version(version("requests")) < Version("2.32"):
sys.exit(f"requests>=2.32 required, found {version('requests')}")
packaging is a third-party package (pip install packaging), though it is present in most environments because pip and many build tools depend on it. Version() rejects strings that are not valid PEP 440 versions with packaging.version.InvalidVersion: Invalid version: 'latest'. For real dependency constraints, declare them in pyproject.toml or a requirements file instead of checking at runtime.
Troubleshooting
- pip says a package is installed, but
importfails (or the reverse). Two interpreters are involved. Comparepython -c "import sys; print(sys.executable)"with theLocationline frompip show, and usepython -m pip. pip: command not found. Usepython -m pip(orpython3 -m pip/py -m pip). If pip itself is missing,python -m ensurepip --upgradeinstalls it.- The version changed but your running program still sees the old one. An already-imported module is not reloaded; restart the process or the Jupyter kernel.
- Two versions appear to be installed. Leftover
.dist-infodirectories from interrupted installs can confuse tools. Reinstall withpython -m pip install --force-reinstall NAME.
Summary
From the shell, use python -m pip show NAME for one package, python -m pip list or pip freeze | grep for an overview, and pip list --outdated or pip index versions NAME for newer releases. From code, use importlib.metadata.version() with the distribution name, treat __version__ as a convenience only, and compare versions with packaging.version.Version, never as strings. In every case, make sure you are querying the same environment that runs your code.
ToolsInstall packages in PyCharm
Install Python packages in PyCharm via the Packages tool window, interpreter settings or pip; venv vs conda, requirements.txt and fixing import errors.
ToolsPython version in Jupyter
Check the Python version a Jupyter kernel really runs with sys.version and sys.executable, avoid the !python --version trap and register a venv as a kernel.
ToolsConvert PDF and DOCX
Convert PDF to Word with pdf2docx and Word to PDF with docx2pdf or headless LibreOffice from Python, including batch jobs, Linux servers and output checks.