Skip to content

Repository files navigation

TsunTrack

🌏 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.

Screenshots

Without installation / when disabled:

zzz

After installation and enabling:

image

Features

  • 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-mean suggestions
  • 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 theme field to an empty string and give it a try.

Installation

Requires Python 3.11+. Install with pip:

pip install tsuntrack

No import needed after installation — just run any script that raises an error and see the result:

python -c "print(1/0)"

Manual Enable / Disable

importtsuntracktsuntrack.install() # Enabletsuntrack.uninstall() # Disable, restoring default behavior

Configuration

Lookup order (highest priority first)

  1. The path specified by the TSUNTRACK_CONFIG environment variable
  2. tsuntrack.toml in the current working directory
  3. ~/.config/tsuntrack/config.toml in the user's home directory
  4. The bundled defaults.toml inside the package

User configuration and defaults are deep-merged — just write the fields you want to change.

Built-in Themes & Languages

Five themes are built in; switch with [general] theme:

ThemeStyleDescription
tsundereTsundereDefault theme; tough on the outside, soft inside
nekoCatgirlCalls you master and serves you dutifully
sarcasticSharp-tonguedBiting sarcasm, but always tells the truth
yandereYandereSweet on the surface, dangerously possessive
chuunibyouChuunibyouEvery 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 as locales/xx.toml, and set language = "xx".

Example

[general]
enabled = true# Master switchtheme = "tsundere"# Current themelanguage = "zh"# Language: zh / enmax_frames = 5# Max stack frames shown (keeps the innermost ones)context_lines = 1# Lines of context code to showerror_line_style = "bold red"# Highlight color for the error lineline_number_style = "dim"# Line-number colorshow_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 ╯^╰'

Themes

The configuration merges in three layers, highest priority first:

  1. User config (tsuntrack.toml / file specified by the env var / ~/.config/...) — directly overrides anything below
  2. Theme override layer ([theme."theme-name".*]) — overrides the base config according to the theme selected by [general] theme
  3. Base config (the parts of defaults.toml other than [theme.*]) — shared by all themes, with exceptions.default as 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}'

Placeholders

PlaceholderMeaningExample
{name}Variable / attribute / module / key name (NameError, AttributeError, ModuleNotFoundError, KeyError, etc.)some_undefined_name
{message}The exception's own message textdivision by zero
{exc_type}Exception type nameNameError
{filename}Path of the file where the error occurred (innermost stack frame)C:\demo\app.py
{lineno}Line number of the error8
{func_name}Name of the function where the error occurredlevel_1
{module}Name of the module where the error occurredapp

Custom placeholders ([extra])

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"})

Disabling

[general]
enabled = false

Put this in a config file at any priority level to disable globally (the hooks will not be installed).

Known Limitations

  • sys.unraisablehook is not handled yet
  • asyncio intrudes into the global policy; for uvloop we can only wrap it for now

    If another library also replaces sys.excepthook, it may silently override this one

  • In modes such as python -S (which doesn't load site), .pth files are not executed, so you need to call tsuntrack.install() manually

License

MIT

About

Make Python's error messages tsundere~ Zero-intrusion, purely configuration-driven global exception beautifier, drop-in and use.让 Python 的报错变得傲娇起来~ 零侵入、纯配置驱动的全局异常美化器,安装即用

Topics

Resources

Stars

2 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages