🌏 Language: 简体中文 | English
Make Python errors tsundere~
A global exception beautifier built on rich — zero-intrusion, purely configuration-driven, install-and-go, and shipped with a built-in tsundere personality.
Without installation / when disabled:
After installation and enabling:
- Theme switching: errors are no longer cold, bare stack traces. Change one line —
[general] theme = "..."— and freely switch to any style: sarcastic, healing, chuunibyou… whatever you like - Install & go: hooks are installed automatically at interpreter startup via
tsuntrack_auto.pth; zero changes to your business code - Configuration-driven: all error messages and styles come from a TOML config; colors are customizable, with support for partial overrides and extended placeholders
- Manual API: you can also enable it manually with
import tsuntrack; tsuntrack.install() - Smart hint enhancement: keeps and beautifies Python's native
did-you-meansuggestions - Rich text: stack traces come with syntax highlighting and multiple themes; the config supports Rich markup such as
[green]/[red] - Coroutine & thread support
Just want the error beautification? Set the
themefield to an empty string and give it a try.
Requires Python 3.11+. Install with pip:
pip install tsuntrackNo import needed after installation — just run any script that raises an error and see the result:
python -c "print(1/0)"import tsuntrack
tsuntrack.install() # Enable
tsuntrack.uninstall() # Disable, restoring default behavior- The path specified by the
TSUNTRACK_CONFIGenvironment variable tsuntrack.tomlin the current working directory~/.config/tsuntrack/config.tomlin the user's home directory- The bundled
defaults.tomlinside the package
User configuration and defaults are deep-merged — just write the fields you want to change.
Five themes are built in; switch with [general] theme:
| Theme | Style | Description |
|---|---|---|
tsundere |
Tsundere | Default theme; tough on the outside, soft inside |
neko |
Catgirl | Calls you master and serves you dutifully |
sarcastic |
Sharp-tongued | Biting sarcasm, but always tells the truth |
yandere |
Yandere | Sweet on the surface, dangerously possessive |
chuunibyou |
Chuunibyou | Every error comes with an anime trope |
Two languages are built in; switch with [general] language (default en): zh (Simplified Chinese) / en (English)
Want to contribute a new language or a new theme? copy
locales/en.toml, translate it, save it aslocales/xx.toml, and setlanguage = "xx".
[general]
enabled = true # Master switch
theme = "tsundere" # Current theme
language = "zh" # Language: zh / en
max_frames = 5 # Max stack frames shown (keeps the innermost ones)
context_lines = 1 # Lines of context code to show
error_line_style = "bold red" # Highlight color for the error line
line_number_style = "dim" # Line-number color
show_hints = true # Whether to show hints
# Context code highlighting:
[general.syntax]
# - theme: a built-in Pygments theme name (e.g. monokai / default / emacs / friendly / tango)
theme = "monokai"
[general.syntax.styles]
# - styles: Pygments token name → Rich style. Token names such as Keyword / Name.Function / String.Doc.
# Keys must be real Pygments tokens; made-up ones are hidden by default.
"Comment.Special" = "bold #5C6370"
"Comment" = "#5C6370"
"String.Doc" = "italic #5C6370"
"String" = "#98C379"
...
# Override the message for a specific exception inside a theme
[theme."tsundere".exceptions.NameError]
template = 'You dummy! I-I would never tell you that "{name}" is not defined. Hmph ╯^╰'The configuration merges in three layers, highest priority first:
- User config (
tsuntrack.toml/ file specified by the env var /~/.config/...) — directly overrides anything below - Theme override layer (
[theme."theme-name".*]) — overrides the base config according to the theme selected by[general] theme - Base config (the parts of
defaults.tomlother than[theme.*]) — shared by all themes, withexceptions.defaultas the fallback
# 1) Switch built-in themes
[general]
theme = "tsundere"
# 2) Override any config directly
[exceptions.NameError]
template = 'My custom message: {name}'
# 3) Custom themes (just add a [theme."name"...] section to your own config)
[general]
theme = "我的主题"
[theme."我的主题".exceptions.NameError]
template = 'My theme message: {name}'| Placeholder | Meaning | Example |
|---|---|---|
{name} |
Variable / attribute / module / key name (NameError, AttributeError, ModuleNotFoundError, KeyError, etc.) | some_undefined_name |
{message} |
The exception's own message text | division by zero |
{exc_type} |
Exception type name | NameError |
{filename} |
Path of the file where the error occurred (innermost stack frame) | C:\demo\app.py |
{lineno} |
Line number of the error | 8 |
{func_name} |
Name of the function where the error occurred | level_1 |
{module} |
Name of the module where the error occurred | app |
You can add an [extra] section to your user config or a theme to define arbitrary extra placeholders:
# tsuntrack.toml (or the config specified by the environment variable)
[extra]
service = "order-api"
env = "production"[theme."neko".exceptions.default]
template = 'Master, {service} failed in the {env} environment ┭┮﹏┭┮: {message}. Leave it to me!'Output: Master, order-api failed in production ┭┮﹏┭┮: ...
- Keys in
[extra]override built-in fields when they share a name with one in[general] - The theme layer works the same way:
[theme."X".extra]lets you define different placeholders per theme - You can also call it from code:
formatter.format_message(exc_type, exc_value, tb, cfg, extra={"service": "x"})
[general]
enabled = falsePut this in a config file at any priority level to disable globally (the hooks will not be installed).
sys.unraisablehookis not handled yetasynciointrudes into the global policy; foruvloopwe can only wrap it for nowIf another library also replaces
sys.excepthook, it may silently override this one- In modes such as
python -S(which doesn't loadsite),.pthfiles are not executed, so you need to calltsuntrack.install()manually
MIT