prettypretty
Prettypretty’s color support is hefty enough to warrant its own subpackage with its own colorful documentation page. Prettypretty also comes with a couple of demo scripts. They are much less hefty but do command their own documentation
prettypretty.ansi
Low-level support for assembling ANSI escape sequences
- prettypretty.ansi.is_default(color: ColorSpec) bool [source]
Determine whether the color specification represents the default color.
- prettypretty.ansi.DEFAULT_COLOR = ColorSpec(tag='ansi', coordinates=(-1,))
The default color for terminals. ANSI escape sequences actually support two default colors, one for the foreground and one for the background. Prettypretty does not support converting the default color into any other color. But it does represent it as either an ANSI or 8-bit color with -1 as its only component.
- class prettypretty.ansi.Layer(value, names=<not given>, *values, module=None, qualname=None, type=None, start=1, boundary=None)[source]
The display layer.
- TEXT
is in front, in the foreground
- BACKGROUND
is behind the text
The enumeration constant values capture the fact that the SGR parameters for setting background color are the same as those for setting text color shifted by 10, i.e., from 30–39 and 90–97 to 40–49 and 100–107. Hence the value of
TEXT
is 0 and that ofBACKGROUND
is 10.
- class prettypretty.ansi.Ansi(value, names=<not given>, *values, module=None, qualname=None, type=None, start=1, boundary=None)[source]
An enumeration of ANSI escape sequence components.
- ESC
is the escape character by itself
- CSI, DCS, OSC
start ANSI escape sequences; they are defined with the two-character C0 sequences and not the one-character C1 sequences, since the latter conflict with UTF-8
- BEL, ST
are interchangeable and terminate OSC sequences; the latter, again, is defined using the two-character C0 sequence.
All enumeration constants are strings and hence can be directly used when assembling ANSI escape sequences. For example:
print(f"{Ansi.CSI}1m" "Parrot!" f"{Ansi.CSI}m")
The example prints a bold excited parrot to the terminal. It leverages Python’s support for splitting string literals into more than one successive literal for clarity and the fact that missing ANSI parameters default to 0 in the second ANSI escape sequence.
Since ANSI escape sequences usually are more complex than the above, this class also defines
color_parameters()
for converting colors to ANSI escape sequence parameters andfuse()
for fusing all these parts into a complete ANSI escape sequence. Using the methods, we can improve on the above example as follows:print( Ansi.fuse(Ansi.CSI, *Ansi.color_parameters(40), 1, 'm'), 'Parrot!', Ansi.fuse(Ansi.CSI, 'm'), )
The example prints a green, bold, excited parrot thanks to the 8-bit color 40. Fuse not only joins its arguments, but it also inserts semicolons between parameters. In other words, the above example prints the same as the following statement:
print("\x1b[38;5;40;1m" "Parrot!" "\x1b[m")
The example is, again, leveraging Python’s support for multiple consecutive string literals for improved clarity. Ironically, the Sphinx documentation processor mangles an escaped escape character
\x1b
, which is now written with an escaped backslash in the docstring source. Apparently, there is value in hiding escape characters behind enumeration constants…- static color_parameters(layer: Layer, color: int, /, use_ansi: bool = ...) tuple[int, ...] [source]
- static color_parameters(layer: Layer, r: int, g: int, b: int, /) tuple[int, ...]
Convert the 8-bit color, RGB256 coordinates, or default color to parameters for an SGR ANSI escape sequence. The default color takes on the code point before the start of the 8-bit color code points, i.e., -1. The layer argument determines whether the resulting parameters update the foreground or background color. To maximize compatibility, this method uses 30–37, 40–47, 90–97, and 100–107 as parameters for setting the 16 extended ANSI color and the triple 38, 5,
color
only for the remaining 240 8-bit colors.
- static fuse(*fragments: None | int | str) str [source]
Fuse the ANSI escape sequence fragments into a single string. This method treats
None
as a default parameter and replaces it with an empty string. It also inserts semicolons between parameters, i.e., when two successive arguments are eitherNone
or an integer.
- class prettypretty.ansi.RawAnsi(value, names=<not given>, *values, module=None, qualname=None, type=None, start=1, boundary=None)[source]
An enumeration of raw ANSi escape sequence components.
This is a simpler,
bytes
-valued version ofAnsi
; see its documentation for more details.- BEL
- CSI
- DCS
- ST
prettypretty.darkmode
- prettypretty.darkmode.is_dark_theme(theme: None | Theme = None) bool [source]
Determine whether the given terminal theme is a dark theme. If not theme is provided, this function uses the current theme. To detect dark themes, this function converts the default foreground and background colors to the XYZ color space and then compares their Y or luminance components. If the foreground has higher luminance than the background, the theme is a dark theme.
- prettypretty.darkmode.is_dark_mode() None | bool [source]
Determine whether the operating system is in dark mode.
- Returns:
True
for dark mode,False
for light mode, andNone
if the mode could not be determined.
The implementation builds on answers to [this StackOverflow question](https://stackoverflow.com/questions/65294987/detect-os-dark-mode-in-python) and [the darkdetect package](https://github.com/albertosottile/darkdetect). The latter seems both over- and under-engineered. In contrast, this module provides the one interesting bit, whether the system is in dark mode, if available and nothing else.
prettypretty.fidelity
- class prettypretty.fidelity.Fidelity(value, names=<not given>, *values, module=None, qualname=None, type=None, start=1, boundary=None)[source]
A terminal’s color fidelity.
- PLAIN
- NOCOLOR
- ANSI
- EIGHT_BIT
- RGB256
When it comes to terminal color support, there are four levels, starting with no-color, then the 16 extended ANSI colors, then 8-bit colors, which directly incorporate ANSI colors, and finally “truecolor,” i.e., RGB256. Since no-color still allows for styling text with ANSI escape codes, fidelity also includes the plain level, which prohibits the use of escapes.
Even though there is no established mapping between ANSI and RGB256 colors, the latter nonetheless subsumes ANSI, most certainly when it comes to display hardware. Historically, no-color was the norm for terminals. In fact, even though DEC’s VT100 series of terminals popularized ANSI escape codes, none of the models in that series had color monitors. Nowadays, no-color is important for modelling restricted runtime environments, e.g., as found on continuous integration services. Meanwhile plain is important when producing machine-readable output. Furthermore, both no-color and plain can capture user preferences.
The original use case for fidelity levels is serving as bounds that restrict renderable colors—and renderable styles in case of the plain level. Unless the bound is plain or no-color, color formats and spaces outside the bound need to be converted to one of the formats within the bound. In almost all cases, that means converting a color to the bound’s format (denoted by the bound’s name in lower case).
However, there are three complications.
When the fidelity level is RGB256, the original color may very well be outside of RGB256’s gamut as well. Since gamut mapping is more accurate with floating point coordinates, preparing colors for RGB256 requires first conversion to sRGB, then gamut mapping, and finally conversion to RGB256.
Since RGB6 is a three-component version of (part of) 8-bit color, converting to 8-bit color suffices for fidelity levels of 8-bit and RGB256. In the latter case, 8-bit color may not be the bound’s format but it certainly is within the bound. Converting RGB6 to 8-bit is a reasonable first step for ANSI fidelity, too.
When the fidelity level is ANSI and the original color is 8-bit with a component value between -1 and 15 inclusive, a trivial re-tagging of the color suffices. Technically, -1 stands for the default color. But that color is part of the core ANSI colors, too.
A second use case helps avoid repeated inspections and attempted conversions when colors may be shared and reused through style objects. It is based on the observation that a fidelity level can also serve as a concise summary of past color conversions. Here,
NOCOLOR
implies a lack of colors and no fidelity implies a lack of inspection.Fidelity levels form a total order and support Python’s comparison operators.
- property tag: str
The corresponding color format or space tag.
- classmethod from_tag(tag: Literal['plain', 'nocolor', 'ansi', 'eight_bit', 'rgb256'] | Self) Self [source]
Instantiate the fidelity level from a tag.
- classmethod from_color(color: None | ColorSpec) None | Fidelity [source]
Determine the fidelity required for the given color specification. If the color is
None
, the required fidelity isNOCOLOR
. However, if the color has a tag other thanansi
,rgb6
,eight_bit
, orrgb256
, this method returnsNone
, indicating that no fidelity can accommodate the given color.
- is_renderable(tag: str) bool [source]
Determine whether the given color format or space is renderable at this terminal fidelity without further preparation including conversion.
If the color format or space is not renderable at this fidelity, colors should be converted to the fidelity level, except that RGB6 should be converted to 8-bit color for RGB256 fidelity.
- prepare_to_render(color: None | ColorSpec) None | ColorSpec [source]
Prepare the color for rendering at this fidelity level. This method accepts null colors and, if this fidelity level is
NOCOLOR
, returns null colors.This method correctly handles the three corner cases for color preparation. First, independent of fidelity level, it converts RGB6 to 8-bit before considering further conversions. Second, instead of directly converting to RGB256, it first converts to sRGB, then gamut-maps the result, and only then converts to RGB256. Finally, when converting to ANSI, it simply re-tags 8-bit colors between -1 and 15.
- prettypretty.fidelity.environment_fidelity(is_tty: bool) Fidelity [source]
Determine the current terminal’s fidelity based on the environment variables for this process. This function incorporates logic from the supports-color package. The
istty
argument indicates whether the terminal’s output is a TTY.
prettypretty.ident
- prettypretty.ident.identify_terminal() None | tuple[str, str] [source]
Identify the current terminal.
This function implements the fallback strategies for
Terminal.request_terminal_identity()
.
- prettypretty.ident.normalize_terminal_name(name: str) str [source]
Normalize the terminal name or bundle ID.
If the given name is an alias for a well-known terminal, this function returns the canonical name. Otherwise, it just returns the given name.
- prettypretty.ident.lookup_term_program_version() None | str [source]
Look up the term program version.
prettypretty.style
High-level support for terminal styles.
A terminal style covers the full repertoire of text attributes controllable via ANSI escape codes. In addition to a fluent interface for assembling styles in the first place, terminal styles support an algebra of inversion and difference to easily compute the minimal changes necessary for restoring the default appearance or transitioning to another appearance.
Reifying terminal styles this way not only simplifies updating the terminal, but it also encourages the definition of terminal styles in a dedicated module. Such an application-wide style registry greatly simplifies the reuse of styles. They all are defined in the same module after all. Centralization also helps with tuning styles so that they harmonize with each other and the design guidelines. In case where no such guidelines exist, a central module may just help define them.
- class prettypretty.style.TextAttribute(value, names=<not given>, *values, module=None, qualname=None, type=None, start=1, boundary=None)[source]
The superclass of all enumerations representing what should be orthogonal stylistic choices. Each enumeration represents a choice of values, which is binary in the common case and ternary for
Weight
. It also encodes the default state by aliasing theDEFAULT
attribute. Finally, it encodes SGR parameters, which are the values of the enumeration constants.__invert__()
uses the above information to automatically determine which text attributes must be set to restore the default appearance of terminal output again.- property is_default: bool
Determine whether the text attribute is the default value.
- class prettypretty.style.Weight(value, names=<not given>, *values, module=None, qualname=None, type=None, start=1, boundary=None)[source]
The font weight.
- REGULAR
is the regular, medium weight
- DEFAULT
marks the regular weight as the default
- BOLD
is a heavier weight
- LIGHT
is a lighter weight
- class prettypretty.style.Slant(value, names=<not given>, *values, module=None, qualname=None, type=None, start=1, boundary=None)[source]
The slant.
- UPRIGHT
is text without slant
- DEFAULT
marks upright text as the default
- ITALIC
is text that is very much slanted
- class prettypretty.style.Underline(value, names=<not given>, *values, module=None, qualname=None, type=None, start=1, boundary=None)[source]
Underlined or not.
- NOT_UNDERLINED
has no inferior line
- DEFAULT
marks the lack of lines as the default
- UNDERLINED
has inferior line
- class prettypretty.style.Overline(value, names=<not given>, *values, module=None, qualname=None, type=None, start=1, boundary=None)[source]
Overlined or not.
- NOT_OVERLINED
has no superior line
- DEFAULT
marks the lack of lines as the default
- OVERLINED
has superior line
- class prettypretty.style.Strikeline(value, names=<not given>, *values, module=None, qualname=None, type=None, start=1, boundary=None)[source]
Stricken or not.
- NOT_STRICKEN
has no line through
- DEFAULT
marks the lack of lines as the default
- STRICKEN
has a line through
- class prettypretty.style.Coloring(value, names=<not given>, *values, module=None, qualname=None, type=None, start=1, boundary=None)[source]
Reversed or not.
- NOT_REVERSED
is the inconspicuous, regular order
- DEFAULT
marks the regular order as the default
- REVERSED
reverses foreground and background colors
- class prettypretty.style.Visibility(value, names=<not given>, *values, module=None, qualname=None, type=None, start=1, boundary=None)[source]
The visibility of text.
- NOT_HIDDEN
makes text visible
- DEFAULT
marks visible text as the default
- HIDDEN
makes text invisible
- prettypretty.style.invert_attr(attr: None | TA) None | TA [source]
Invert the given text attribute.
- prettypretty.style.invert_color(color: None | ColorSpec) None | ColorSpec [source]
Invert the given color.
- class prettypretty.style.Instruction[source]
The superclass of all terminal instructions available to rich text.
- class prettypretty.style.Style(*, weight: None | Weight = None, slant: None | Slant = None, underline: None | Underline = None, overline: None | Overline = None, strikeline: None | Strikeline = None, coloring: None | Coloring = None, visibility: None | Visibility = None, foreground: None | ColorSpec = None, background: None | ColorSpec = None)[source]
A terminal style.
- strikeline
for lines through
- Type:
None | Strikeline
- visibility
for visibility
- Type:
None | Visibility
- fidelity
is the minimum color fidelity and computed automatically, with
None
indicating unbounded fidelity- Type:
None | Fidelity
This class captures the state of all text attributes controllable through ANSI escape sequences. It distinguishes between:
setting an attribute, e.g., when
underline
isUnderline.UNDERLINED
;unsetting an attribute, e.g., when
underline
isUnderline.NOT_UNDERLINED
;ignoring an attribute, e.g., when
underline
isNone
.
Since colors may just have to be downsampled or discarded for rendering even if styles only allow color formats directly supported by ANSI escape sequences, this class accepts all color formats and spaces while having robust facilities for adjusting formats as needed.
The
fidelity
attribute is automatically computed during initialization and identifies the minimum fidelity level needed for rendering this style. A null fidelity indicates that this style contains arbitrary colors and hence has unbounded fidelity. MeanwhileFidelity.NOCOLOR
indicates that the style does not contain any colors andFidelity.PLAIN
indicates an empty style.Note
Styles overload Python’s inversion operator. The result of that operation is another style that restores the terminal to its default appearance. Styles also overload Python’s subtraction operator, which returns the style that incrementally transitions from the second to the first style. Finally, the string representation of styles is the corresponding SGR ANSI escape sequence.
Instances of this class are immutable.
- property plain: bool
The flag for an empty style specification.
- class prettypretty.style.Link(text: str, href: str, id: None | str = None)[source]
A hyperlink.
- text
- Type:
str
- href
- Type:
str
- id
- Type:
None | str
- class prettypretty.style.PlaceCursor(row: None | int = None, column: None | int = None)[source]
Cursor placement by row and column.
- row
- Type:
None | int
- column
- Type:
None | int
- class prettypretty.style.MoveCursor(move: Literal['up', 'down', 'left', 'right', 'column'], offset: None | int = None)[source]
Cursor movement along one dimension.
- move
- Type:
Literal[‘up’, ‘down’, ‘left’, ‘right’, ‘column’]
- offset
- Type:
None | int
- prettypretty.style.RichTextElement: TypeAlias = str | prettypretty.style.Instruction
The type of all rich text elements.
- class prettypretty.style.RichText(fragments: tuple[str | Instruction, ...])[source]
The terminal version of rich text mixes text, which is to be rendered literally, and style specifications, which are to be rendered as SGR ANSI escape codes. The terminal version of rich text also tracks the current fidelity level and can be easily prepared for a different fidelity.
- classmethod of(*fragments: str | Instruction) Self [source]
Create a rich text object from the the given fragments.
- class prettypretty.style.rich(incremental: bool = False)[source]
A rich builder.
This class helps create styles and rich text through fluent property accesses and method invocations. In addition to text attributes and colors, it also tracks cursor movements and hyperlinks.
A rich builder can have isolated or incremental styles. Isolated styles are the default for builders created by
rich()
, whereas builders created byrich.incremental()
have incremental styles. The trade-off is that, with isolated styles, you don’t need to worry about undoing styles because this class does that for you. However, you do need to worry about all styles standing on their own and cannot rely on the previous style contributing attributes. It’s just the opposite for incremental styles. You can rely on the attributes of the previous style and incrementally add to them. But you also need to undo your own styles.For isolated and incremental styles alike, if you want to undo the current style without setting a new style, you can just call
undo_style()
and let prettypretty figure out the needed antistyle. For isolated styles, that always is the empty style. For incremental styles, that style may just depend on all preceding styles.- style() Style [source]
- style(style: Style) Self
Get or add a style.
If invoked without arguments, this method returns the last updated style. It does not consider any preceding styles, even if this rich builder is in incremental mode.
If invoked with a style argument, this method adds the style to the rich text sequence being built. Whether the style is treated as isolated or incremental depends on this rich builder’s mode.
- emit(close_style: bool = True) RichText [source]
Emit the built rich text sequence.
This method computes effective styles to fill locations that undo the current style. As long as the argument allows, it also adds a closing style to restore the terminal’s default appearance if there isn’t one.
- property regular: Self
Update style with regular weight.
- property light: Self
Update style with light weight.
- property bold: Self
Update style with bold weight.
- property upright: Self
Update style with upright.
- property italic: Self
Update style with italic.
- property not_underlined: Self
Update style with not underlined.
- property underlined: Self
Update style with underlined.
- property not_overlined: Self
Update style with not overlined.
- property overlined: Self
Update style with overlined.
- property not_stricken: Self
Update style with not stricken.
- property stricken: Self
Update style with stricken.
- property not_reversed: Self
Update style with background and foreground colors reversed.
- property reversed: Self
Update style with background and foreground colors reversed.
Update style with not hidden.
Update style with hidden.
- fg(color: int, /) Self [source]
- fg(c1: int, c2: int, c3: int, /) Self
- fg(color: ColorSpec, /) Self
- fg(tag: str, c: int, /) Self
- fg(tag: str, coordinates: CoordinateSpec, /) Self
- fg(tag: str, c1: float, c2: float, c3: float, /) Self
Update style with foreground color.
- bg(color: int, /) Self [source]
- bg(c1: int, c2: int, c3: int, /) Self
- bg(color: ColorSpec, /) Self
- bg(tag: str, c: int, /) Self
- bg(tag: str, coordinates: CoordinateSpec, /) Self
- bg(tag: str, c1: float, c2: float, c3: float, /) Self
Update style with background color.
prettypretty.terminal
- class prettypretty.terminal.BatchMode(value, names=<not given>, *values, module=None, qualname=None, type=None, start=1, boundary=None)[source]
A terminal’s batch mode.
- NOT_SUPPORTED
indicates that the terminal does not support batching
- ENABLED
indicates that the terminal is currently batching
- DISABLED
indicates that the terminal is not currently batching
- UNDEFINED
really is permanently enabled, which makes no sense
- PERMANENTLY_DISABLED
effectively is the same as the terminal not supporting batch mode
Since three out of five status codes for batching more (
NOT_SUPPORTED
,PERMANENTLY_DISABLED
) or less (UNDEFINED
) imply that the terminal doesn’t support batching, this enumeration also defines the more precise computed propertiesis_supported
,is_enabled
, andis_disabled
.- property is_supported: bool
Determine whether the terminal supports batching.
- property is_enabled: bool
Determine whether the terminal is currently batching.
- property is_disabled: bool
Determine whether the terminal is currently not batching.
- class prettypretty.terminal.TerminalContextManager(terminal: Terminal)[source]
A context manager for terminal state.
This class manages operations that update and restore terminal state. It ensures that all updates are applied on entry and restored on exit, that updates are applied in registration order and restored in the opposite order, and that terminal output is flushed after applying and also after reverting all updates.
An update may be a pair of escape sequences or a function that instantiates a context manager. In case of the former, the first sequence is written to the output upon entry and the second sequence upon exit. In case of the latter, the function and its result’s
__enter__()
method are invoked on entry and the result’s__exit__()
method is invoked on exit. Currently, there is no public interface for registering the latter.This class is reentrant and reusable, though an instance does nothing on nested invocations.
Terminal
has several methods with the same names and signatures as this class. They are the preferred way of creating terminal context manager instances because they are far more convenient. For example, to get started using prettypretty, you might write:terminal = Terminal() with TerminalContextManager(terminal).terminal_theme().scoped_style(): ...
is equivalent to this far nicer alternative
with Terminal().alternate_screen().hidden_cursor() as terminal: ...
- register(do: str, undo: str) Self [source]
Register an update with this terminal context manager. Both
do
andundo
should be ANSI escape sequences, withundo
restoring the terminal to the state from beforedo
.
- cbreak_mode() Self [source]
Put the terminal into cbreak mode.
If the terminal is not yet in cbreak mode, the context manager sets cbreak mode upon entry and restores the previous mode upon exit. If the terminal is in cbreak mode already, the context manager does not modify the terminal mode, but it still restores the previous mode upon exit. Mode changes only take effect after all queued output has been written but queued input is discarded.
- terminal_theme(theme: None | Theme = None) Self [source]
Use the terminal’s color theme. Unless a theme is provided as argument, the context manager puts the terminal temporarily into cbreak mode and determines the current theme colors upon entry. It then makes that theme the current theme until exit.
Make cursor invisible.
- batched_output() Self [source]
Batch terminal output.
While batching, a terminal temporarily delays updating the screen by buffering output. It avoids visual artifacts when rapidly updating the screen.
- bracketed_paste() Self [source]
Enable bracketed pasting.
- class prettypretty.terminal.Terminal(input: None | TextIO = None, output: None | TextIO = None, fidelity: None | Fidelity | Literal['plain', 'nocolor', 'ansi', 'eight_bit', 'rgb256'] = None)[source]
Terminal input/output.
This class manages terminal input and output. It encapsulates the nitty gritty of managing the terminal with ANSI escape codes behind methods with meaningful, human-readable names instead of cryptic mnemonics (what does ED do again and how does it differ from DECSED?). Furthermore, many operations that would leave the terminal in an unusable state upon
This class supports the following features:
- Terminal window size
Terminal
caches the width and height of the terminal. It only updates the cached values if an application explicitly polls for changes. That way, the application is hopefully prepared to accommodate a terminal size change as well.See
width
,height
,request_size()
,update_size()
, andcheck_same_size()
.- Cbreak mode
In this mode, the terminal does not support line editing; instead, it immediately forwards bytes. As such cbreak mode facilitates request/response interactions between application and terminal. Getting authoritative information from the terminal sure beats other, more indirect ways, such as environment variables, that help surmise specific conditions.
See
is_cbreak_mode()
,check_cbreak_mode()
, andcbreak_mode()
.- Writing to terminal output
This class exposes different methods for writing text and for writing control sequences. The latter automatically fuses fragments together, adding semicolons between empty and numeric parameters. It also checks that the terminal supports ANSI escapes. Finally, it provides a convenient hook for intercepting them.
See
write()
,writeln()
:,write_control()
, andflush()
; alsofidelity
,check_output_tty()
, andcheck_tty()
.- Reading terminal input and ingesting ANSI escapes
Python’s standard library has extensive support for reading from streams, but only blocking calls including for line-oriented input are convenient to use. This class makes up for that by implementing support for character-oriented, non-blocking input as well as for ANSI escape sequences. The latter require three levels of parsing:
Parse individual character to read an entire control sequence, no less, no more.
Parse message to to separate the integral or textual payload from message header and tail.
Parse text to extract terminal name, colors, etc.
See
read()
andread_control()
; alsomake_raw_request()
,parse_textual_response()
, andparse_numeric_response()
; alsorequest_terminal_identity()
,request_cursor_position()
,request_batch_mode()
,request_ansi_color()
,request_dynamic_color()
, andrequest_theme()
.- Scoped changes of terminal state
To more easily update, restore, and flush terminal states,
Terminal
delegates to a terminal context manager. It makes it possible to fluently queue up all restorable updates in a singlewith
statement without worrying about many of the implementation details.See
cbreak_mode()
,terminal_theme()
,window_title()
,alternate_screen()
,hidden_cursor()
,batched_output()
,bracketed_paste()
, andscoped_style()
.- Simple updates of terminal state
Some terminal updates, notably for positioning the cursor and for erasing (parts of) the screen need not or can not be easily undone but still are eminently useful. You can also move the cursor and write links in
rich
text.See
up()
,down()
,left()
,right()
,set_position()
,set_column()
,erase_screen()
,erase_line()
, andlink()
.- Setting terminal styles
What’s the point of integrating terminal colors with robust color management? Styling terminal output, of course! This class has methods to set bold, italic, or plain text and to set the fore/background colors. Those methods do not, however, adjust to the runtime context. For that, you want to use prettypretty’s
Style
objects andrich()
text.See
reset_style()
,rich_text()
,bold()
,italic()
,fg()
, andbg()
.
- property width: int
The cached terminal width.
- property height: int
The cached terminal height.
- request_size() None | tuple[int, int] [source]
Determine the terminal’s size in fixed-width columns and rows. If the underlying platform hook fails for both input and output, typically because both input and output have been redirected, this method returns
None
.
- check_same_size() Self [source]
Check that the terminal size has not changed since the last update.
- is_cbreak_mode(mode: None | list[Any] = None) bool [source]
” Determine whether cbreak mode is enabled. This method inspects the current terminal mode to see whether characters are not echoed (
ECHO
is not set), line editing is disabled (ICANON
is not set), and reads return upon the first available character (VMIN
is 1,VTIME
is 0).Since raw mode makes the same changes and then some, this method detects raw mode as cbreak mode. That’s just fine for its intended purpose, which is checking whether the terminal is prepared for handling ANSI escape sequences that require ANSI escape sequences as responses.
- check_cbreak_mode() Self [source]
Check that cbreak mode is enabled. THis method signals an exception if cbreak mode is not enabled.
- cbreak_mode() TerminalContextManager [source]
Put the terminal into cbreak mode.
If the terminal is not yet in cbreak mode, the context manager sets cbreak mode upon entry and restores the previous mode upon exit. If the terminal is in cbreak mode already, the context manager does not modify the terminal mode, but it still restores the previous mode upon exit. Mode changes only take effect after all queued output has been written but queued input is discarded.
- write(*fragments: str) Self [source]
Write the string fragments to this terminal’s output. This method does not flush the output.
- writeln(*fragments: str) Self [source]
Write the string fragments followed by a line terminator to this terminal’s output. This method does not flush the output.
- write_paragraph(text: str) Self [source]
Write the paragraph to this terminal’s output.
This method strips all leading and trailing white space from each line of the text. It then treats each span of consecutive, non-empty lines as a paragraph and rewraps it to fit into the terminal width while still being convenient to read. Finally, it writes the resulting text to this terminal’s output. This method does not flush the output.
- write_control(*fragments: None | int | str) Self [source]
Write a control sequence to this terminal.
This method
fuses
the fragments of the inline control sequence (i.e., ANSI escape sequence) into a string and writes that string to this terminal’s output. This method does not flush the terminal’s output.This terminal’s fidelity must not be
Fidelity.PLAIN
, which is the case if the output is not a TTY. That restriction applies to all methods that write control sequences, since they always delegate to this method.
- read(*, length: int = 3, timeout: float = 0) bytes [source]
Read raw bytes from this terminal.
This method reads up to
length
bytes from this terminal. If thetimeout
is 0, this method does not wait for input and immediately returns, possibly with an empty byte string. If thetimeout
is greater than 0, this method does wait for input, up to as many seconds, usingselect()
.This terminal must be in cbreak mode.
- read_control() bytes [source]
Read a complete ANSI escape sequence from this terminal.
This method implements a reasonable but not entirely complete state machine for parsing ANSI escape sequences and keeps calling
read()
for more bytes as necessary. It usesESCAPE_TIMEOUT
as timeout.The terminal must have TTYs for input and output. It also must be in cbreak mode.
- make_raw_request(*query: None | int | str) None | bytes [source]
Make a request to this terminal. This method writes an ANSI escape sequence to this terminal as a query and then reads an ANSI escape sequence as the response.
The terminal must have TTYs for input and output. It also must be in cbreak mode.
- parse_textual_response(response: None | bytes, prefix: str, suffix: str) None | str [source]
Parse the terminal’s textual response to an ANSI escape query.
This method converts the response to a string, checks that is starts with the prefix and ends with the suffix, and then returns the text between prefix and suffix. If the suffix is ST, this method also allows BEL, as both are used interchangeably for terminating DSC/OSC.
If the response is
None
or malformed, this method returnsNone
.
- parse_numeric_response(response: None | bytes, prefix: bytes, suffix: bytes) list[int] [source]
Parse the terminal’s numeric response to an ANSI escape query.
This method checks that the given response starts with the prefix and ends with the suffix, splits the bytes between prefix and suffix by semicolons, and parses the resulting byte fragments as integers. Empty byte fragments are parsed as -1. If the suffix ends with ST, this method also allows BEL, as both are used interchangeably for terminating DSC/OSC.
If the response is
None
or malformed, this method returns an empty list.
- request_terminal_identity() None | tuple[str, str] [source]
Request the terminal name and version.
Since support for the CSI >q escape sequence for querying a terminal for its name and version is far from universal, this method employs the following strategies:
Use CSI >q escape sequence to query terminal.
Inspect the
TERMINAL_PROGRAM
andTERMINAL_PROGRAM_VERSION
environment variables.On macOS only, get the bundle identifier from the
__CFBundleIdentifier
environment variable and then use themdfind
andmdls
command line tools to extract the bundle’s version.
If any of these methods is successful, this method normalizes the terminal name based on a list of known aliases. That includes bundle identifiers for Linux and macOS. It also caches the result and returns it for future invocations.
The terminal must have TTYs for input and output. It also must be in cbreak mode.
- request_cursor_position() None | tuple[int, int] [source]
Request the cursor position in (x, y) order from this terminal.
The terminal must have TTYs for input and output. It also must be in cbreak mode.
- request_batch_mode() BatchMode [source]
Determine the terminal’s current batch mode.
The terminal must have TTYs for input and output. It also must be in cbreak mode.
- request_active_style() list[int] [source]
Request the terminal’s current style settings.
The returned list contains the corresponding SGR parameters. Terminals differ significantly in their support for this query. Since just this query would help determine color support levels, that is rather ironic. For instance, macOS Terminal.app does not handle the query, whereas Visual Studio Code’s builtin terminal and iTerm 2 both respond with well-formed styles, which are completely wrong in case of Visual Studio Code.
The terminal must have TTYs for input and output. It also must be in cbreak mode.
- request_color_support() None | Fidelity [source]
Request the terminal’s color support.
This method uses style queries to test for 24-bit and 8-bit color.
The terminal must have TTYs for input and output. It also must be in cbreak mode. This method resets the current style.
- request_ansi_color(color: int) ColorSpec [source]
Determine the color for the given extended ANSI color. This method queries the terminal, parses the result, which by convention uses four hexadecimal digits per component, and normalizes it to sRGB.
The terminal must have TTYs for input and output. It also must be in cbreak mode.
- request_dynamic_color(code: int) ColorSpec [source]
Determine the color for the user interface element identified by
code
:10 is the foreground or text color
11 is the background color
This method queries the terminal, parses the result, which by convention uses four hexadecimal digits per component, and normalizes it to sRGB.
The terminal must have TTYs for input and output. It also must be in cbreak mode.
- request_theme() Theme
Request all theme colors from the terminal.
Currently, there are three different implementations of this method:
The first version completely processes one color at a time. It writes the query, then reads the response, and then parses the response.
The second version operates in two phases: It first writes all 18 queries and then reads and parses all 18 responses.
The third version operates in three phases: It first writes all 18 queries, then reads all 18 responses, and finally parses all 18 responses.
In my measurements, the second and third version take only half the time of the first version and, usually, the third version is a bit faster still. But I have seen a couple of spurious failures for terminal queries and hence expect the need for some retry logic, which would complicate things. So for now, I am not ready to commit to either of those three versions. If you feel like experimenting, you can run the microbenchmarks by running this module:
python -m prettypretty.terminal
You can also switch between versions by updating the assignment above this documentation comment in the source code. In either case, please report back about your experiences by filing an issue.
The terminal must have TTYs for input and output. It also must be in cbreak mode.
- terminal_theme(theme: None | Theme = None) TerminalContextManager [source]
Use a different color theme. Unless a theme argument is provided, the implementation queries the terminal for its current theme, while temporarily putting the terminal in cbreak mode.
- window_title(title: str) TerminalContextManager [source]
Use a different window title.
- alternate_screen() TerminalContextManager [source]
Switch to the terminal’s alternate (unbuffered) screen.
Make cursor invisible.
- batched_output() TerminalContextManager [source]
Batch terminal output.
- bracketed_paste() TerminalContextManager [source]
Enable bracketed pasting.
- scoped_style() TerminalContextManager [source]
Scope style changes by resetting the style on exit. The
style()
context helps protect against unwanted style leakage upon unexpected exceptions or signals.
- at(row: None | int = None, column: None | int = None) Self [source]
Move the cursor to the given row and column.
- link(text: str, href: str, id: None | str = None) Self [source]
-
Underlined text should only be used for hyperlinks, in terminal emulators just as much as in documents and on web pages. That’s just why this class does not have a separate method for styling text as underlined. If that’s too stringent for your use case, please do open an issue.
- rich_text(fragments: Sequence[RichTextElement]) Self [source]
- rich_text(*fragments: RichTextElement) Self
Write rich text to terminal output