Why do we all love Python? For starters, it’s a beautiful and easy-to-learn programming language. Another reason: it comes with batteries included, meaning Python has many excellent libraries included by default. But in my opinion, it’s the more than 900,000 user-contributed packages on PyPI that make Python really powerful and popular.
In this article, I handpicked 15 of the best Python packages: the ones I find most useful, plus a few that have become essential in recent years. Let’s go!
How to install these packages
All of these packages live on PyPI, the Python Package Index. Install them inside a virtual environment, not in your system Python. Many Linux distributions and Homebrew block pip install outside a virtual environment anyway. Inside an activated venv, use pip install:
pip install richCode language: Python (python)
If your project uses uv, use uv add rich instead. Replace rich with the name of any package below.
The 15 best Python packages
1. Dash
Dash is ideal for building data visualization apps in pure Python, so it’s particularly suited for anyone who works with data. Dash is a blend of Flask, Plotly.js, and React.js.

Dash allows you to quickly scaffold the stuff you need into a beautiful dashboard without the need to touch a single line of JavaScript.
2. Pygame
Pygame is a Python wrapper module for the SDL multimedia library. Simple DirectMedia Layer is a cross-platform development library designed to provide low-level access to:
- audio
- keyboard
- mouse
- joystick
- graphics hardware via OpenGL and Direct3D
Pygame is highly portable and runs on nearly every platform and operating system. It’s a library for making games, but you can also use it to simply play an MP3 file right from your Python scripts.
There are two versions. The original pygame hasn’t had a release in a while and doesn’t provide packages for the newest Python versions. Most of its developers now work on the community edition, pygame-ce, which is a drop-in replacement. Install it with pip install pygame-ce, and you still write import pygame in your code.
3. Pillow
Pillow is a fork of the Python Imaging Library (PIL). You can use the library to create thumbnails, convert between file formats, rotate, apply filters, display images, and more. It’s ideal if you need to perform batch operations on many images.
To get a quick feel for it, this is how you can open an image, look at its properties and save a thumbnail:
from PIL import Image
im = Image.open("kittens.jpg")
print(im.format, im.size, im.mode)
# JPEG (1920, 1357) RGB
im.thumbnail((400, 400))
im.save("kittens-small.jpg")
print(im.size)
# (400, 283)
To look at an image, call im.show(), which opens it in your default image viewer. You can do all of this right from the Python shell (REPL) or IPython:

See the documentation for all the features.
4. Rich
With Rich, you can add color and style to your terminal output. It does a lot more than color, though: it pretty-prints data structures, draws tables and progress bars, renders Markdown, and shows readable tracebacks. Here’s a small taste:
from rich import print
from rich.table import Table
from rich.console import Console
print("[bold red]Hello[/bold red], [green]world[/green]! :thumbs_up:")
print({"name": "Erik", "languages": ["Python", "Bash"]})
table = Table(title="Packages")
table.add_column("Name")
table.add_column("Used for")
table.add_row("rich", "Pretty terminal output")
table.add_row("tqdm", "Progress bars")
Console().print(table)
In your terminal, the first line is in color and the dictionary is syntax highlighted. Without the colors, the output looks like this:
Hello, world! 👍
{'name': 'Erik', 'languages': ['Python', 'Bash']}
Packages
┏━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━━┓
┃ Name ┃ Used for ┃
┡━━━━━━╇━━━━━━━━━━━━━━━━━━━━━━━━┩
│ rich │ Pretty terminal output │
│ tqdm │ Progress bars │
└──────┴────────────────────────┘
If all you need is a bit of color, the smaller Colorama package works too. Modern terminals, including Windows Terminal, understand color codes out of the box. For the old Windows console, call Colorama’s just_fix_windows_console() once at the start of your program.
5. JMESPath
Using JSON in Python is super easy since JSON maps so well on a Python dictionary. Additionally, Python comes with its own excellent json library to parse and create JSON. For me, it’s one of its best features. If I need to work with JSON, I turn to Python in a reflex. (If you ever need to process huge amounts of JSON very fast, have a look at orjson.)

But there’s something you might not realize you’re missing. If you just use json.loads() and get data from the dictionary manually, perhaps with a for-loop here and there, you’re in for a surprise.
JMESPath, pronounced “James path”, makes JSON in Python even easier. It allows you to declaratively specify how to extract elements from a JSON document. Here are some basic examples to give you a feeling for what it can do:
import jmespath
# Get a specific element
d = {"foo": {"bar": "baz"}}
print(jmespath.search('foo.bar', d))
# baz
# Using a wildcard to get all names
d = {"foo": {"bar": [{"name": "one"}, {"name": "two"}]}}
print(jmespath.search('foo.bar[*].name', d))
# ['one', 'two']
This is just touching the surface of all its possibilities. Read my JMESPath tutorial, or see the documentation and the PyPI page for more.
6. Requests and HTTPX
Requests is built on one of the most downloaded Python libraries in the world, urllib3. It makes web requests really simple, yet remains very powerful and versatile. Chances are you know this one by heart already, but I couldn’t make this list without mentioning it! It’s the best-known Python package when it comes to HTTP.
Just to show how easy requests can be, let’s ask the GitHub API for information about the requests project itself:
import requests
r = requests.get('https://api.github.com/repos/psf/requests')
print(r.status_code)
# 200
print(r.headers['content-type'])
# application/json; charset=utf-8
print(r.encoding)
# utf-8
data = r.json()
print(data['full_name'], data['license']['spdx_id'])
# psf/requests Apache-2.0
That is a very basic example, but requests can also do all the advanced stuff you can think of, like:
- Authentication
- Using cookies
- Performing POSTs, PUTs, DELETEs, etc.
- Using custom certificates
- Working with sessions
- Working with proxies
- … and so much more!
If you need async support or HTTP/2, look at HTTPX. Its API is almost the same as that of requests, so httpx.get(url) works just like you’d expect, and it also offers an async client for use with asyncio.
Links:
7. Pydantic
Pydantic validates data using ordinary type hints. You describe what your data should look like, and Pydantic checks and converts incoming data for you. That’s very useful for anything that comes from outside your program: JSON from an API, a config file, or a web form.
from pydantic import BaseModel, ValidationError
class User(BaseModel):
name: str
age: int
email: str | None = None
user = User(name="Erik", age="38")
print(user)
# name='Erik' age=38 email=None
print(user.model_dump_json())
# {"name":"Erik","age":38,"email":null}
try:
User(name="Erik", age="old")
except ValidationError as e:
print(e)
Notice how the string "38" was converted to the integer 38. The second user fails with a clear message:
1 validation error for User
age
Input should be a valid integer, unable to parse string as an integer [type=int_parsing, input_value='old', input_type=str]
For further information visit https://errors.pydantic.dev/2.14/v/int_parsing
If you only need a simple container for data inside your own code, the built-in data classes are often enough. Use Pydantic when the data needs checking.
8. FastAPI
FastAPI is a web framework for building APIs. It uses type hints and Pydantic to validate requests, and it generates interactive API documentation for you. This is a complete API with two endpoints, saved as main.py:
from fastapi import FastAPI
from pydantic import BaseModel
app = FastAPI()
class Item(BaseModel):
name: str
price: float
@app.get("/hello/{name}")
def hello(name: str):
return {"message": f"Hello, {name}!"}
@app.post("/items")
def create_item(item: Item):
return {"created": item.name, "price_with_tax": round(item.price * 1.21, 2)}
Install it with pip install "fastapi[standard]" and start the development server with fastapi dev main.py. Then try it from another terminal:
$ curl http://127.0.0.1:8000/hello/Erik
{"message":"Hello, Erik!"}
$ curl -X POST http://127.0.0.1:8000/items -H 'Content-Type: application/json' -d '{"name": "Book", "price": 10}'
{"created":"Book","price_with_tax":12.1}
If you leave out the price, FastAPI answers with a 422 error that explains what’s missing. Open http://127.0.0.1:8000/docs in your browser to see and try the generated documentation. Want to build one step by step? Read my article on how to create a Python REST API.
9. Polars
Polars is a DataFrame library, like pandas, written in Rust. It’s very fast, uses all your CPU cores, and has a consistent API that many people find easier to read than pandas. Say you have a file sales.csv with the columns city, product and amount. Here’s how to get the total sales per city:
import polars as pl
df = pl.read_csv("sales.csv")
result = (
df.group_by("city")
.agg(pl.col("amount").sum().alias("total"))
.sort("total", descending=True)
)
print(result)
shape: (3, 2) ┌───────────┬───────┐ │ city ┆ total │ │ --- ┆ --- │ │ str ┆ f64 │ ╞═══════════╪═══════╡ │ Amsterdam ┆ 15.0 │ │ Rotterdam ┆ 11.0 │ │ Utrecht ┆ 10.0 │ └───────────┴───────┘
pandas is still the most used DataFrame library, and you’ll find it everywhere. I use it in my article on processing Excel data. For new projects with lots of data, Polars is well worth a try.
10. Python-dateutil
The python-dateutil module provides powerful extensions to the standard datetime module. It’s my experience that where regular Python datetime functionality ends, python-dateutil comes in.
You can do so much cool stuff with this library. One feature I find particularly useful is fuzzy parsing of dates from log files and such:
from dateutil.parser import parse logline = 'INFO 2026-01-01T00:00:01 Happy new year, human.' timestamp = parse(logline, fuzzy=True) print(timestamp) # 2026-01-01 00:00:01
Another is relativedelta, which does calendar math that timedelta can’t, like “one month later” or “next Monday”:
from datetime import date from dateutil.relativedelta import relativedelta, MO today = date(2026, 11, 10) print(today + relativedelta(months=+1)) # 2026-12-10 print(today + relativedelta(weekday=MO(+1))) # 2026-11-16 print(date(2026, 1, 31) + relativedelta(months=+1)) # 2026-02-28
See the full documentation for more features, like:
- Computing of dates based on recurrence rules, using a superset of the iCalendar specification.
- Computing of Easter Sunday dates for any given year, using Western, Orthodox, or Julian algorithms.
For time zones, you no longer need dateutil: the standard library has the zoneinfo module, as in ZoneInfo("Europe/Amsterdam").
11. Progress bars with tqdm
You can create your own progress bar, which is fun to do perhaps, but it’s quicker and less error-prone to use a package. My favorite is tqdm. Wrap any iterable in tqdm(), and you get a progress bar:
import time
from tqdm import tqdm
for i in tqdm(range(100)):
time.sleep(0.01) # do some work
100%|██████████| 100/100 [00:01<00:00, 84.45it/s]
tqdm on the command line

tqdm has an extra trick up its sleeve: it can be used on the command line, in a pipe, like this:
$ tar -zcf - docs/ | tqdm --bytes --total `du -sb docs/ | cut -f1` > backup.tgz 32%|██████████▍ | 8.89G/27.9G [00:42<01:31, 223MB/s]
More examples and documentation can be found on the tqdm GitHub page. If you already use Rich, it has progress bars too: from rich.progress import track, and then loop over track(range(20)).
12. IPython

I’m sure you are aware of the Python interactive shell. It’s a great way to tinker with Python. But do you know the IPython shell as well? If you use the interactive shell a lot and you don’t know IPython, you should really check this one out!
Some of the features the enhanced IPython shell offers are:
- Comprehensive object introspection.
- Input history, persistent across sessions.
- Caching of output results during a session with automatically generated references.
- Tab completion, with support for completion of python variables and keywords, filenames, and Python functions.
- ‘Magic’ commands for controlling the environment and performing many tasks related either to IPython or the operating system.
- Session logging and reloading.
- Integrated access to the pdb debugger and the Python profiler.
The standard Python shell has caught up a bit: since Python 3.13 it has colors, multi-line editing and better history. IPython still offers a lot more. If you’re interested, you can get some quick getting started hints to IPython usage from my article on it. IPython is also the core of Jupyter Notebook, an open-source web application that allows you to create and share documents that contain live code, equations, visualizations, and narrative text.
13. Home Assistant

I love home automation. It’s a bit of a hobby for me, but also something I’m dead serious about since by now it’s controlling large parts of our house. I tied together all systems in our house by using Home Assistant. It’s a complete application written in Python, and you can even install its core as a PyPI package.
- Most of our lamps are automated and our blind as well.
- I monitor our gas usage and power usage and production (solar panels).
- I can track the location of most of our phones, and start actions when they enter a zone, like switching on the garage lights when I come home.
- It can also control all our entertainment systems, like our Samsung TV and Sonos speakers.
- It’s able to auto-discover most devices on your network, so it’s really easy to get started.
I’ve been using Home Assistant daily for years now, and it’s by far the best platform of all the ones I tried. It’s able to integrate and control all kinds of devices and protocols, and it’s all free and open source.
If you’re interested in automating your home, make sure to give it a chance! The easiest way to start is to install Home Assistant OS on a Raspberry Pi or a small PC; the installation page explains your options. I run it on a more powerful server, inside a Docker container.
14. Flask

Flask is my go-to library for creating a quick website. It’s a microframework, which means Flask aims to keep the core simple but extensible. There are hundreds of extensions, both official and from the community. For an API that mainly returns JSON, FastAPI (below) is the more common choice today.
If you know you’ll be developing a huge web app, you might want to look into a more complete framework instead. The most popular in that category is Django.
15. Beautiful Soup
If you’ve pulled some HTML from a website, you need to parse it to get what you actually need. Beautiful Soup is a Python library for pulling data out of HTML and XML files. It provides simple methods for navigating, searching, and modifying a parse tree. It is very powerful and is able to handle all kinds of HTML, even if it’s broken. And believe me, HTML is often broken, so this is a very powerful feature. In this example, the second link is missing its closing tag:
from bs4 import BeautifulSoup
html = """
<html><body>
<h1>My links</h1>
<a href="/?u=https%3A%2F%2Fpython.land%2F">Python Land</a>
<a href="/?u=https%3A%2F%2Fdocs.python.org%2F3%2F">Python docs
</body></html>
"""
soup = BeautifulSoup(html, "html.parser")
print(soup.h1.text)
for link in soup.find_all("a"):
print(link.text.strip(), "->", link["href"])
My links Python Land -> https://python.land Python docs -> https://docs.python.org/3/
Some of its main features:
- Beautiful Soup automatically converts incoming documents to Unicode and outgoing documents to UTF-8. You don’t have to think about encodings.
- Beautiful Soup sits on top of popular Python parsers like
lxmlandhtml5lib, allowing you to try out different parsing strategies or trade speed for flexibility. - Beautiful Soup parses anything you give it and does the tree traversal stuff for you. You can tell it “Find all the links”, or “Find the table heading that’s got bold text, then give me that text.”
Install it with pip install beautifulsoup4, and read the documentation to learn more.
Bonus: tools every Python developer should know
The packages above are libraries you import in your code. These three are tools you use while developing, and I’d install them on any project:
- pytest is the standard way to write and run tests in Python. A test is just a function whose name starts with
test_and that uses a plainassert. - Ruff is an extremely fast linter and code formatter. It replaces a whole collection of older tools, like flake8, isort and Black.
- uv installs Python itself, manages your virtual environments and dependencies, and runs tools. I wrote a full uv tutorial.
What did I miss?
There you have it: my pick of the best Python packages. Is there something missing in this list? Feel free to leave a comment!