It feels like—after three decades—the Python world is experiencing a renaissance, both in tooling and in libraries. It’s an exciting time to be a Python developer.
We’ve seen exciting libraries like Pydantic and FastAPI picking up steam, which is fantastic.
That said, there are also some smaller utilities that are gems in their own right. Some, like pytest-sugar, can be dropped into a project with minimal fuss. Others, like ptpython, can be used by an individual on a team without impacting the team.
Here are four can’t-live-without Python tools that I’ve recently added to my dev utility belt because they make me a faster developer (and they’re doggone fun to use):
4. ptpython
Website: https://github.com/prompt-toolkit/ptpython
Installation: python -m pip install ptpython
, Python 3.6+
Ptpython is what the built-in Python REPL ought to be. Just take a look at these features!
Syntax highlighting

Autocompletion

Autoindentation
Watch ptpython automatically indent the body of this class; I didn’t have to manually add tabs or spaces!

Multiline editing
In this example, I forgot to include the age
attribute when I initially defined the class. I hit the up arrow once and now I can edit the entire multiline block of that particular class.

Syntax errors
Ptpython will catch syntax errors before you execute the line, giving you a chance to go back and fix them before execution. And yes, it works with multiline blocks.

I haven’t even gotten into Emacs/Vi modes, IPython compatibility, displaying docstrings and function signatures, running shell commands without leaving the REPL, and host of other features. The next two tools are the peanut butter to ptpython’s chocolate, so install it and get ready for even more fun!
3. devtools, rich, and icecream
Website: https://python-devtools.helpmanual.io/
Installation: python -m pip install devtools
, Python 3.7+
Website: https://github.com/Textualize/rich
Installation: python -m pip install rich
, Python 3.7+
Website: https://github.com/gruns/icecream
Installation: python -m pip install icecream
, Python 2, 3
The next tool is a three-fer: devtools, rich, and IceCream are all great libraries and which one I reach for just depends on how I’m feeling at the moment. They all make printing complex data structures so much nicer than Python’s pprint
. They also have more tricks up their sleaves than just pretty printing. Let’s dig in…
devtools.debug()
debug
is like
The devtools Usage page has a colorful-but-apt description of what debug
does. It will pretty print as many variables as you can throw at it, along with the file name, line number, and function where debug
is being invoked.

Additionally, debug
returns what you pass into it, meaning you can insert it into your code without changing functionality:

devtools.debug.timer()
You can also use the timer
function to do basic timings on operations:

devtools.debug.breakpoint()
Finally, you can use debug.breakpoint()
to invoke pdb
:

rich.print()
Similar to devtools.debug()
, rich.print()
is a better pretty printer. Unlike devtools.debug()
, which is solely focused on debugging, rich.print()
supports a slew of formatting options, such as shortcodes (including emojis).

rich.inspect()
rich.inspect()
is a nice tool for digging into variables; it shows the type, the contained values, and optionally methods, private, and dunder attributes. Note: if “dunder” is a new term for you, it refers to attributes with double underscores around them, like __init__
; “double underscore” gets tiresome to say, so you’ll frequently see that shortened to “dunder” in the Python world.

icecream.ic()
ic()
is pretty similar to the other two libraries but with the added advantage that it’s even faster to type!

It will print both the variable name and its value, with syntax highlighting.

Like devtools.debug()
it’ll return what you passed in, so you can inline it in your code.

One additional neat trick is that you can scatter it throughout your code like debugging breadcrumbs and it’ll inspect itself, leaving you with a trail of exactly which lines in the code were triggered:

2. pytest-sugar
Website: https://github.com/Teemu/pytest-sugar
Installation: python -m pip install pytest-sugar
, Python 3.8+, pytest 6.2+
pytest-sugar is a drop-in (automatically activated) plugin for pytest. It does several things to make your tests look and work better:
- Errors are reported immediately; no waiting to see what broke
- A progress bar visualizes how far you’ve progressed through the suite
- Colored summary report
Here’s a test suite without pytest-sugar:

And the same test suite with pytest-sugar:

1. Ruff
Website: https://docs.astral.sh/ruff/
Installation: python -m pip install pytest-sugar
, Python 3.7+
Ruff is an extremely fast Python linter. In addition to its speed, I also appreciate its sensible default settings and large ruleset.
Linting in Python is worth its own blog post, so I’ll try to summarize here. The question, “what linter should I use for Python?” always felt fraught with uncertainty and complications. I’ve seen many projects end up with autopep8, flake8, pylint, bandit, and isort and nobody knows which are still used … or even what they’re used for.
Ruff replaces them all.
It’s hard to understate just how little work we’ve had to do to switch to Ruff at my current client: we just swapped the dependencies out, deleted all the non-Ruff configuration, and were good to go. We started migrating to Ruff when we upgraded to SQLAlchemy 2.0 and ran into a bug that caused our pylint runs to be unbearably slow. The bug is now fixed as of pylint 3; however, our switch to Ruff was so easy that we didn’t need to wait around for that fix to land.
As Ruff matures, we continue to replace tools. The most recent swap was pulling bandit for Ruff’s flake8-bandit ruleset. We’re keeping an eye on the Ruff Formatter, and it seems likely that we’ll be replacing Black soon. (Black is another tool I love, and it would be on this list if it weren’t for Ruff moving towards feature parity.)
BONUS: VS Code Extensions
Because you made it this far, I’ll throw in two recently-discovered, favorite VS Code extensions:
indent-rainbow
Makes your indent levels both pretty and easy to read!

gitmoji
Spice up your commit messages with gitmojis, because every commit log should be as beautiful as FastAPI’s.

Want to continue the conversation about Python tooling? Join our N.E.A.T. community or if you’re already registered, head on over to the forum to talk Python tool tips!