@@ -75,7 +75,34 @@ class ANSIColors:
7575 setattr (NoColors , attr , "" )
7676
7777
78+ #
79+ # Experimental theming support (see gh-133346)
80+ #
81+
82+ # - create a theme by copying an existing `Theme` with one or more sections
83+ # replaced, using `default_theme.copy_with()`;
84+ # - create a theme section by copying an existing `ThemeSection` with one or
85+ # more colors replaced, using for example `default_theme.repl.copy_with()`;
86+ # - create a theme from scratch by instantiating a `Theme` data class with
87+ # the required sections (with are also dataclass instances).
88+ #
89+ # Then call `_colorize.set_theme(your_theme)` to set it.
90+ #
91+ # Put your theme configuration in $PYTHONSTARTUP for the interactive shell,
92+ # or sitecustomize.py in your virtual environment or Python installation for
93+ # other uses. Your applications can call `_colorize.set_theme()` too.
94+ #
95+ # Note that thanks to the dataclasses providing default values for all fields,
96+ # creating a new theme or theme section from scratch is possible without
97+ # specifying all keys.
98+
99+
78100class ThemeSection (Mapping [str , str ]):
101+ """A mixin/base class for theme sections.
102+
103+ It enables dictionary access to a section, as well as implements convenience
104+ methods.
105+ """
79106 __dataclass_fields__ : ClassVar [dict [str , Field [str ]]]
80107 _name_to_value : Callable [[str ], str ]
81108
@@ -145,6 +172,11 @@ class Unittest(ThemeSection):
145172
146173@dataclass (frozen = True )
147174class Theme :
175+ """A suite of themes for all sections of Python.
176+
177+ When adding a new one, remember to also modify `copy_with` and `no_colors`
178+ below.
179+ """
148180 repl : REPL = field (default_factory = REPL )
149181 traceback : Traceback = field (default_factory = Traceback )
150182 unittest : Unittest = field (default_factory = Unittest )
@@ -156,13 +188,24 @@ def copy_with(
156188 traceback : Traceback | None = None ,
157189 unittest : Unittest | None = None ,
158190 ) -> Self :
191+ """Return a new Theme based on this instance with some sections replaced.
192+
193+ Themes are immutable to protect against accidental modifications that
194+ could lead to invalid terminal states.
195+ """
159196 return type (self )(
160197 repl = repl or self .repl ,
161198 traceback = traceback or self .traceback ,
162199 unittest = unittest or self .unittest ,
163200 )
164201
165202 def no_colors (self ) -> Self :
203+ """Return a new Theme where colors in all sections are empty strings.
204+
205+ This allows writing user code as if colors are always used. The color
206+ fields will be ANSI color code strings when colorization is desired
207+ and possible, and empty strings otherwise.
208+ """
166209 return type (self )(
167210 repl = self .repl .no_colors (),
168211 traceback = self .traceback .no_colors (),
@@ -232,6 +275,18 @@ def get_theme(
232275 force_color : bool = False ,
233276 force_no_color : bool = False ,
234277) -> Theme :
278+ """Returns the currently set theme, potentially in a zero-color variant.
279+
280+ In cases where colorizing is not possible (see `can_colorize`), the returned
281+ theme contains all empty strings in all color definitions.
282+ See `Theme.no_colors()` for more information.
283+
284+ It is recommended not to cache the result of this function for extended
285+ periods of time because the user might influence theme selection by
286+ the interactive shell, a debugger, or application-specific code. The
287+ environment (including environment variable state and console configuration
288+ on Windows) can also change in the course of the application life cycle.
289+ """
235290 if force_color or (not force_no_color and can_colorize (file = tty_file )):
236291 return _theme
237292 return theme_no_color
0 commit comments