Skip to content

Theming support for _colorize #133346

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
ambv opened this issue May 3, 2025 · 0 comments
Open

Theming support for _colorize #133346

ambv opened this issue May 3, 2025 · 0 comments
Assignees
Labels
stdlib Python modules in the Lib dir type-feature A feature request or enhancement

Comments

@ambv
Copy link
Contributor

ambv commented May 3, 2025

As mentioned in #131507 and #130645, theming support is an important piece of the puzzle in introducing color to Python output in the terminal.

Design goals

Simplicity of use with type safety

It should be as easy to use theming as to operate with colors by hand.

User configurability through $PYTHONSTARTUP

It should be trivially possible for the user to set up their own favorite colors in their $PYTHONSTARTUP script.

Theme exchange through PyPI

It should be possible for the user to pip install theme-something and set_theme(theme_something.theme) in their $PYTHONSTARTUP and be done with it.

Forward-compatibility of old themes

It should be possible for the user to keep using a theme from 3.14 in future versions of Python without changes. The new color definitions would be automatically taken from the default theme.

Immutability of theme objects

It should be impossible for user code to modify the default theme in place as this can lead to inconsistencies.

Implementation

Types

The _colorize module contains a Theme dataclass, which groups theme sections together. It's immutable. Each theme section corresponds to a theming use case, like the REPL or Argparse. Each theme section is its own dataclass as it will contain keys unique to the use case. Every theme section is also immutable.

For convenience, each theme section inherits from a ThemeSection mixin that provides the theme section with the capability to create a colorless variant or a copy with only some keys modified.

The _colorize module also exposes a default_theme and theme_no_color globals. Those can be copied to create derivative themes.

Using themes in stdlib code

Python standard libraries using color themes should be using the get_theme() function exclusively. This function will return the currently configured theme. If the end user disabled colors or stdout is not a TTY, the returned theme will contain empty strings for every theme section key. This allows the standard library using color themes to program assuming colors everywhere, and they will turn into no-ops in environments where color should not be emitted.

Implementations can optionally also directly call can_colorize() to avoid costly color-specific operations like parsing source code to syntax highlight it.

Importantly, standard libraries should never cache output of get_theme() and can_colorize() as those values can change during the execution of the program:

  • the end user can switch out a theme after your standard library was already imported;
  • they can switch out a theme in the interactive shell or through PDB;
  • can_colorize() might return a different answer if os.environ changes or the console mode changes (possible on Windows).

Configuration

The end user can import _colorize in their $PYTHONSTARTUP script and use set_theme() to set it to a new value. This new value can be:

  • a theme created in-place using regular dataclass instantiation and the convenience .copy_with() methods;
  • a theme imported from another module, possibly installed from PyPI.

In non-interactive use of Python, the $PYTHONSTARTUP file is not executed. For such use cases, customizing the theme can be achieved through a sitecustomize or a usercustomize module.

Rejected Ideas

Introduce a new configuration file

There are already too many configuration files. Given Python's extensible nature, a format like TOML or INI would become insufficient. This would require a lengthy discussion, in which time no theming support would be available to users at all.

Use simple dictionaries

This is easier to implement but makes type-checking harder, allows user code to override color codes at will (which can lead to broken terminal output), and provides less conveniences for creating derivative themes from the default one.

Introduce a theme like $LS_COLORS to $PYTHON_COLORS

Since there are many theming sections, the resulting string format would have to be very human-unfriendly. Setting it would affect Python-based applications that might want to handle theming themselves. Priority would be unclear.

Open issues

Rename _colorize to colorize

There's frankly very little time for this before Python 3.14 beta 1. I would rather keep the library name underscored for 3.14 and gather feedback from the community on the format and behavior, and introduce a stable API in Python 3.15, keeping _colorize for backward compatibility.

Linked PRs

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
stdlib Python modules in the Lib dir type-feature A feature request or enhancement
Projects
None yet
Development

No branches or pull requests

2 participants