Beautiful, readable Python tracebacks with colors and formatting
Project description
Beautiful, Readable Python Stack Traces
Human readable stacktraces for Python.
[!NOTE] This is a fork of the pretty-traceback repo with simplified development and improvements for better integration with FastAPI, structlog, IPython, pytest, and more. This project is used in python-starter-template to provide better debugging experience in production environments.
Quick Start
The fastest way to see it in action:
# Clone and run an example
git clone https://github.com/iloveitaly/beautiful-traceback
cd beautiful-traceback
uv run examples/simple.py
Overview
Beautiful Traceback groups together what belongs together, adds coloring and alignment. All of this makes it easier for you to see patterns and filter out the signal from the noise. This tabular format is best viewed in a wide terminal.
Installation
uv add beautiful-traceback
Usage
Add the following to your __main__.py or the equivalent module which is your entry point.
try:
import beautiful_traceback
beautiful_traceback.install()
except ImportError:
pass # no need to fail because of missing dev dependency
Please do not add this code e.g. to your __init__.py or any other module that your users may import. They may not want you to mess with how their tracebacks are printed.
[!NOTE] If you must call
install()in shared code, setBEAUTIFUL_TRACEBACK_ENABLED=trueonly in environments where you want it active. When the env var is absent or falsy,install()is a no-op.
Note, that the hook is only installed if the existing hook is the default. Any existing hooks that were installed before the call of beautiful_traceback.install will be left in place.
LoggingFormatter
A logging.Formatter subclass is also available (e.g. for integration with Flask, FastAPI, etc).
import os
from flask.logging import default_handler
try:
if os.getenv('FLASK_DEBUG') == "1":
import beautiful_traceback
default_handler.setFormatter(beautiful_traceback.LoggingFormatter())
except ImportError:
pass # no need to fail because of missing dev dependency
IPython and Jupyter Integration
Beautiful Traceback works seamlessly in IPython and Jupyter notebooks:
# Load the extension
%load_ext beautiful_traceback
# Unload if needed
%unload_ext beautiful_traceback
The extension automatically installs beautiful tracebacks for your interactive session.
Pytest Integration
Beautiful Traceback includes a pytest plugin that automatically enhances test failure output.
Automatic Activation
The plugin activates automatically when beautiful-traceback is installed. No configuration needed!
Configuration Options
Customize the plugin in your pytest.ini or pyproject.toml:
[tool.pytest.ini_options]
enable_beautiful_traceback = true # Enable/disable the plugin
enable_beautiful_traceback_local_stack_only = true # Show only local code (filter libraries)
beautiful_traceback_show_aliases = false # Hide sys.path aliases section (default: true)
beautiful_traceback_exclude_patterns = [ # Regex patterns to drop frames
"click/core\\.py",
]
Or in pytest.ini:
[pytest]
enable_beautiful_traceback = true
enable_beautiful_traceback_local_stack_only = true
beautiful_traceback_show_aliases = true
beautiful_traceback_exclude_patterns =
click/core\.py
Example: filter out pytest, pluggy, and playwright frames from CI tracebacks:
[tool.pytest.ini_options]
beautiful_traceback_exclude_patterns = [
"^_pytest/",
"^pluggy/",
"^playwright/",
]
Pattern Matching: Patterns are tested against multiple representations of each frame:
_pytest/runner.py(short module path)/path/to/site-packages/_pytest/runner.py(full module path)<site> _pytest/runner.py:353 from_call result: ...(formatted line with short path)<site> /path/to/.../runner.py:353 from_call result: ...(formatted line with full path)
This allows you to write simpler patterns like ^_pytest/ instead of needing to match the full site-packages path.
JSON / Structured Logging
exc_to_json() converts an exception to a JSON-serializable dict, suitable for production log pipelines (structlog, python-json-logger, etc.).
import sys
from beautiful_traceback import exc_to_json
# pass sys.exc_info() directly
try:
...
except Exception:
log.error("unhandled exception", **exc_to_json(sys.exc_info()))
# or pass the exception and traceback separately
try:
...
except Exception as e:
log.error("unhandled exception", **exc_to_json(e, e.__traceback__))
Output shape:
{
"exception": "ValueError",
"message": "something went wrong",
"frames": [
{"module": "app/service.py", "alias": "<pwd>", "function": "process", "lineno": 42}
],
"notes": ["added via exc.add_note(...)"],
"syntax_error": {
"filename": "script.py", "lineno": 10, "offset": 5, "text": "bad code",
"end_lineno": 10, "end_offset": 9, "msg": "invalid syntax"
},
"chain": [
{
"exception": "KeyError",
"message": "'missing_key'",
"relationship": "caused_by",
"frames": [...]
}
]
}
notes is only present when exc.add_note() was called (Python 3.11+). syntax_error is only present for SyntaxError exceptions. chain is only present when the exception has __cause__ or __context__.
Exclude frames by module or file path
If your production logs include frames like these:
{
"alias": "<site>",
"function": "__call__",
"lineno": 60,
"module": "uvicorn/middleware/proxy_headers.py"
}
{
"alias": "<site>",
"function": "__call__",
"lineno": 1160,
"module": "fastapi/applications.py"
}
you can exclude them with exclude_patterns by matching either the short module value, the full file path, or the alias-prefixed rendered line:
import sys
from beautiful_traceback import exc_to_json
try:
...
except Exception:
payload = exc_to_json(
sys.exc_info(),
exclude_patterns=[
# Match the short module value from JSON output.
r"^uvicorn/middleware/proxy_headers\.py$",
r"^fastapi/applications\.py$",
# Match the absolute file path on disk.
r"/site-packages/fastapi/routing\.py$",
r"/site-packages/sentry_sdk/integrations/starlette\.py$",
# Or match a specific deployment path if you want to be exact.
r"^/app/\.venv/lib/python3\.13/site-packages/uvicorn/middleware/proxy_headers\.py$",
],
)
The matcher checks all of these representations for each frame:
uvicorn/middleware/proxy_headers.pyThis is the short module path, relative to the alias root such as<site>or<pwd>./app/.venv/lib/python3.13/site-packages/uvicorn/middleware/proxy_headers.pyThis is the full absolute path on disk.<site> uvicorn/middleware/proxy_headers.py:60 __call__ ...This is the rendered traceback line with the alias and short path.<site> /app/.venv/lib/python3.13/site-packages/uvicorn/middleware/proxy_headers.py:60 __call__ ...This is the rendered traceback line with the alias and full path.
That means you can write broad patterns like ^fastapi/ for alias-relative matching, /site-packages/fastapi/ for absolute path matching, or ^<site> .*fastapi/ if you want to require a specific alias.
The same patterns also work with install() and configure():
If you want to drop a whole integration layer, match the module prefix instead:
exclude_patterns = [
r"^uvicorn/",
r"^fastapi/",
r"^starlette/",
r"^sentry_sdk/integrations/",
]
Global defaults with configure()
Use configure() to set shared defaults for traceback rendering helpers instead of passing them on every call:
from beautiful_traceback import configure, exc_to_json
configure(
local_stack_only=True,
exclude_patterns=[r"site-packages/"],
show_aliases=False,
)
# these options are now applied automatically
try:
...
except Exception:
log.error("unhandled exception", **exc_to_json(sys.exc_info()))
Per-call arguments always override configure() defaults. install() also calls configure() with its explicit formatting options, so shared defaults stay aligned.
Threading Support
beautiful_traceback.install() hooks both sys.excepthook and threading.excepthook, so unhandled exceptions in background threads are automatically formatted.
- Thread name and daemon status are shown in the exception header (e.g.,
Exception in thread Worker-1 (daemon):) exc_to_json()accepts an optionalthreadparameter to include thread metadata in structured JSON output
See examples/threading_example.py for a complete demonstration.
Examples
Check out the examples/ directory for basic usage, exception chaining, logging integration, and more.
Configuration
Installation Options
Beautiful Traceback supports several configuration options:
beautiful_traceback.install(
color=True, # Enable colored output
only_tty=True, # Only activate for TTY output
only_hook_if_default_excepthook=True, # Only install if default hook
local_stack_only=None, # Defaults to BEAUTIFUL_TRACEBACK_LOCAL_STACK_ONLY env var
show_aliases=None, # Defaults to BEAUTIFUL_TRACEBACK_SHOW_ALIASES env var (default: false)
exclude_patterns=["click/core\\.py"], # Regex patterns to drop frames
)
Environment Variables
NO_COLOR- Disables colored output when set (respects no-color.org standard)BEAUTIFUL_TRACEBACK_ENABLED- Set tofalse/0/noto disable. Useful when install() is called in shared code.BEAUTIFUL_TRACEBACK_LOCAL_STACK_ONLY- Set totrue/1/yesto filter out library/framework frames.BEAUTIFUL_TRACEBACK_SHOW_ALIASES- Set tofalse/0/noto hide the sys.path aliases section.
These env vars serve as fallback defaults for both install() and the pytest plugin (CLI args and pytest.ini settings take precedence over env vars for pytest).
LoggingFormatterMixin
For more advanced logging integration, you can use LoggingFormatterMixin as a base class:
import logging
import beautiful_traceback
class MyFormatter(beautiful_traceback.LoggingFormatterMixin, logging.Formatter):
def __init__(self):
super().__init__(fmt='%(levelname)s: %(message)s')
This gives you full control over the log format while adding beautiful traceback support.
Global Installation via PTH File
You can enable beautiful-traceback across all Python projects without modifying any source code by using a .pth file. Python automatically executes import statements in .pth files during interpreter startup, making this perfect for development environments.
Using the CLI Command
The easiest way to inject beautiful-traceback into your current virtual environment:
beautiful-traceback
This command:
- Only works within virtual environments (for safety)
- Installs the
.pthfile into your current environment's site-packages - Displays the installation path every time it runs
Output:
Beautiful traceback injection installed: /path/to/.venv/lib/python3.11/site-packages/beautiful_traceback_injection.pth
Using a Shell Function (Alternative)
Alternatively, add this function to your .zshrc or .bashrc:
# Create a file to automatically import beautiful-traceback on startup
python-inject-beautiful-traceback() {
local site_packages=$(python -c "import site; print(site.getsitepackages()[0])")
local pth_file=$site_packages/beautiful_traceback_injection.pth
local py_file=$site_packages/_beautiful_traceback_injection.py
cat <<'EOF' >"$py_file"
def run_startup_script():
try:
import beautiful_traceback
beautiful_traceback.install(only_tty=False)
except ImportError:
pass
run_startup_script()
EOF
echo "import _beautiful_traceback_injection" >"$pth_file"
echo "Beautiful traceback injection created: $pth_file"
}
After sourcing your shell config, run python-inject-beautiful-traceback to enable beautiful tracebacks globally for that Python environment.
Alternatives
Beautiful Traceback is heavily inspired by the backtrace module by nir0s but there are many others (sorted by github stars):
- https://github.com/qix-/better-exceptions
- https://github.com/cknd/stackprinter
- https://github.com/onelivesleft/PrettyErrors
- https://github.com/skorokithakis/tbvaccine
- https://github.com/aroberge/friendly-traceback
- https://github.com/HallerPatrick/frosch
- https://github.com/nir0s/backtrace
- https://github.com/mbarkhau/pretty-traceback
- https://github.com/staticshock/colored-traceback.py
- https://github.com/chillaranand/ptb
- https://github.com/laurb9/rich-traceback
- https://github.com/willmcgugan/rich#tracebacks
License
This project was created from iloveitaly/python-package-template
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file beautiful_traceback-0.9.0.tar.gz.
File metadata
- Download URL: beautiful_traceback-0.9.0.tar.gz
- Upload date:
- Size: 18.7 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: uv/0.10.11 {"installer":{"name":"uv","version":"0.10.11","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
f534e90430ad1c2bed7d73d3225061698d9d6da29109cc3608b7a0dd63d16e15
|
|
| MD5 |
8cbda9619f31bdfe6464fc16f837403f
|
|
| BLAKE2b-256 |
4cf71fbbafa1b0f7bab6f5af38743dff51c816dc8fac8f582773629d1065ac39
|
File details
Details for the file beautiful_traceback-0.9.0-py3-none-any.whl.
File metadata
- Download URL: beautiful_traceback-0.9.0-py3-none-any.whl
- Upload date:
- Size: 23.3 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: uv/0.10.11 {"installer":{"name":"uv","version":"0.10.11","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
ee37f52e9580638de3541ca901cf1a5f2464bc98c1d2681bb9a69a895f539e88
|
|
| MD5 |
d4e64ff2ce9e04789fdba5483ff66986
|
|
| BLAKE2b-256 |
1185e5221f135ccb35d280e83d8574cf2f3e6422c115dc16ca8413d78510f865
|