Skip to main content

ANSI formatted terminal output toolset

Project description

PyTermor

(yet another) Python library designed for formatting terminal output using ANSI escape codes. Provides a registry with most useful SGR sequences and predefined formats.

Motivation

Key feature of this library is providing necessary abstractions for building complex text sections with lots of formatting, while keeping the application code clear and readable.

Installation

pip install pytermor

Use cases

Format instances are callable; they wraps specified string with preset leading and trailing control sequences.

from pytermor.preset import fmt_yellow, fmt_green, fmt_bg_blue

print(fmt_yellow('Basic'), fmt_bg_blue('text'), fmt_green('coloring'))

Preset formats can safely overlap with each other (as long as they belong to different modifier groups).

from pytermor.preset import fmt_green, fmt_inverse, fmt_underline

msg = fmt_green('Nes' + fmt_inverse('te' + fmt_underline('d fo') + 'rm') + 'ats')
print(msg)
code (click)

Use build_c256() to change text (or background) color to any of xterm-256 colors.

from pytermor import build_c256, build
from pytermor.preset import COLOR_OFF

txt = '256 colors support'
msg = f'{build("bold")}'
start_color = 41
for idx, c in enumerate(range(start_color, start_color+(36*6), 36)):
    msg += f'{build_c256(c)}'
    msg += f'{txt[idx*3:(idx+1)*3]}{COLOR_OFF}'
print(msg)
code (click)

Create your own SGR sequences with build() method, which accepts color/attribute keys, integer param values and even existing SGRs in any order. Keys can be specified using any case.

from pytermor import build
from pytermor.preset import RESET, UNDERLINED

seq1 = build('red', 1, UNDERLINED)  # keys, integer codes or existing sequences
seq2 = build('inversed', 'YELLOW')  # case-insensitive

msg = f'{seq1}Flexible{RESET} ' +
      f'{build(seq1, 3)}sequence{RESET} ' +
      str(seq2) + 'builder' + str(RESET)
print(msg) 
code (click)

It's also possible to create custom wrapper presets which include both starting and ending control sequences.

from pytermor.preset import *

fmt1 = Format(HI_BLUE + BOLD, reset_after=True)
fmt2 = Format(BG_BLACK + INVERSED + UNDERLINED + ITALIC,
              BG_COLOR_OFF + INVERSED_OFF + UNDERLINED_OFF + ITALIC_OFF)
msg = fmt1(f'Custom n{fmt2("establ")}e formats')
print(msg)
code (click)

Mix high-level and low-level abstractions if necessary.

from pytermor.preset import *
from pytermor.sequence import SequenceSGR

msg = f'{CYAN}L{GREEN}ow-{fmt_inverse("l"+str(ITALIC)+"e")}ve{ITALIC_OFF}l ' \
      f'{BG_HI_YELLOW}fo{fmt_underline.open}rm{BG_COLOR_OFF}at ' \
      f'c{SequenceSGR(*MODE8_START.params, 214)}on{RESET}' \
      f'{SequenceSGR(*MODE8_START.params, 208)}t{fmt_underline.close}r{RESET}' \
      f'{SequenceSGR(*MODE8_START.params, 202)}ol{RESET}'
print(msg)

API [module]

build(*params str|int|SequenceSGR) -> SequenceSGR

Creates new SequenceSGR instance with specified params. Resulting sequence params order is the same as argument order. Each param can be specified as:

  • string key (see API: Preset)
  • integer param value
  • existing SequenceSGR instance (params will be extracted)

build_c256(color: int, bg: bool = False) -> SequenceSGR

Creates new SequenceSGR instance either of MODE8_START type (set text color to color), or BG_MODE8_START type (same, but for background color), depending on bg value.

API: SequenceSGR

Class describing SGR-mode ANSI escape sequence with varying amount of parameters.

Details (click)
  • To get the resulting sequence simply cast instance to str:

    from pytermor.sequence import SequenceSGR
    
    seq = str(SequenceSGR(4, 7))   # direct transform with str()
    msg = f'({seq})'               # f-string var substitution
    print(msg + f'{SequenceSGR(0)}',  # f-string value
          str(seq.encode()),
          seq.encode().hex(':'))
    

    1st part consists of "applied" escape sequences; 2nd part shows up one of the sequences in raw mode, as if it was ignored by the terminal; 3rd part is hexademical sequence byte values.

    SGR sequence structure (click)
    1. \x1b|1b is ESC control character, which opens a control sequence.

    2. [ is sequence introducer, it determines the type of control sequence (in this case it's CSI, or "Control Sequence Introducer").

    3. 4 and 7 are parameters of the escape sequence; they mean "underlined" and "inversed" attributes respectively. Those parameters must be separated by ;.

    4. m is sequence terminator; it also determines the sub-type of sequence, in our case SGR, or "Select Graphic Rendition". Sequences of this kind are most commonly encountered.

  • One instance of SequenceSGR can be added to another. This will result in a new SequenceSGR instance with combined params.

    from pytermor import SequenceSGR
    from pytermor.preset import RESET
      
    mixed = SequenceSGR(1, 31) + SequenceSGR(4)
    print(f'{mixed}combined{RESET}', str(mixed).encode())
    
  • Pretty much all single-param sequences (that can be used at least for something) are specified in pytermor.preset module. Example usage:

    from pytermor.preset import BLACK, BG_HI_GREEN, RESET
      
    print(f'{BLACK}{BG_HI_GREEN}', 'Example text', str(RESET))
    

Complete list is given at the end of this document.

API: Format

Format is a wrapper class that contains starting (i.e. opening) SequenceSGR and (optionally) closing SequenceSGR.

Details (click)
  • You can define your own reusable formats or import predefined ones from pytermor.preset:

    from pytermor.format import Format
    from pytermor.preset import HI_RED, COLOR_OFF, fmt_overline
    
    fmt_error = Format(HI_RED, COLOR_OFF)
    print(fmt_overline.open +
        'overline might not work ' +
        fmt_error('>') + ':(' +
        fmt_overline.close)
    
  • The main purpose of Format is to simplify creation of non-resetting text spans, so that developer doesn't have to restore all previously applied formats after every closing sequence (which usually consists of RESET).

  • Example: we are given a text span which is initially bold and underlined. We want to recolor a few words inside of this span. By default this will result in losing all the formatting to the right of updated text span (because RESET|\e[m clears all text attributes).

  • However, there is an option to specify what attributes should be disabled (instead of disabling all of them):

    from pytermor.preset import *
    
    fmt_warn = Format(
      HI_YELLOW + UNDERLINED,  # sequences can be summed up, remember?
      COLOR_OFF + UNDERLINED_OFF,  # "counteractive" sequences
      reset_after=False
    )
    orig_text = fmt_bold(f'{BG_BLACK}this is the original string{RESET}')
    updated_text = orig_text.replace('original', fmt_warn('updated'), 1)
    print(orig_text, '\n', updated_text)
    
  • As you can see, the update went well — we kept all the previously applied formatting. Of course, this method cannot be 100% applicable — for example, imagine that original text was colored blue. After the update "string" word won't be blue anymore, as we used COLOR_OFF escape sequence to neutralize our own red color. But it still can be helpful for a majority of cases (especially when text is generated and formatted by the same program and in one go).


API: StringFilter

Common string modifier interface with dynamic configuration support.

Details (click)

Subclasses

  • ReplaceSGR
  • ReplaceCSI
  • ReplaceNonAsciiBytes

Standalone usage

  • Can be executed with .invoke() method or with direct call.

    from pytermor.preset import fmt_red
    from pytermor.string_filter import ReplaceSGR
    
    formatted = fmt_red('this text is red')
    replaced = ReplaceSGR('[LIE]').invoke(formatted)
    # or directly:
    # replaced = ReplaceSequenceSGRs('[LIE]')(formatted)
    
    print(formatted, '\n', replaced)
    

Usage with apply_filters

  • apply_filters accepts both StringFilter (and subclasses) instances and subclass types, but latter is not configurable and will be invoked using default settings.

    from pytermor import apply_filters
    from pytermor.string_filter import ReplaceNonAsciiBytes
    
    ascii_and_binary = b'\xc0\xff\xeeQWE\xffRT\xeb\x00\xc0\xcd\xed'
    
    # can either provide filter by type:
    # result = apply_filters(ascii_and_binary, ReplaceNonAsciiBytes)
    # ..or instantiate and configure it:
    result = apply_filters(ascii_and_binary, ReplaceNonAsciiBytes(b'.'))
    
    print(ascii_and_binary, '\n', result)
    

API: Preset

Sequence and format registry.

SGR sequences (click)
  • var — variable name defined in pytermor.preset;
  • key — string that will be recognised by build() method;
  • params — list of default CSI params for specified seqeunce.
var key params comment
RESET "reset" 0 disables all colors and attributes
attributes
BOLD "bold" 1
DIM "dim" 2
ITALIC "italic" 3
UNDERLINED "underlined" 4
BLINK_SLOW "blink_slow" 5
BLINK_FAST "blink_fast" 6
INVERSED "inversed" 7
HIDDEN "hidden" 8
CROSSLINED "crosslined" 9
DOUBLE_UNDERLINED "double_underlined" 21
OVERLINED "overlined" 53
DIM_BOLD_OFF "dim_bold_off" 22
ITALIC_OFF "italic_off" 23
UNDERLINED_OFF "underlined_off" 24
BLINK_OFF "blink_off" 25
INVERSED_OFF "inversed_off" 27
HIDDEN_OFF "hidden_off" 28
CROSSLINED_OFF "crosslined_off" 29
OVERLINED_OFF "overlined_off" 55
text colors
BLACK "black" 30
RED "red" 31
GREEN "green" 32
YELLOW "yellow" 33
BLUE "blue" 34
MAGENTA "magenta" 35
CYAN "cyan" 36
WHITE "white" 37
MODE24_START "mode24_start" 38 2 set text color to specified;
3 more params required: r,g,b
valid values: [0-255]
MODE8_START "mode8_start" 38 5 set text color to specified;
1 more param required: code
valid value: [0-255]
COLOR_OFF "color_off" 39 reset text color
background colors
BG_BLACK "bg_black" 40
BG_RED "bg_red" 41
BG_GREEN "bg_green" 42
BG_YELLOW "bg_yellow" 43
BG_BLUE "bg_blue" 44
BG_MAGENTA "bg_magenta" 45
BG_CYAN "bg_cyan" 46
BG_WHITE "bg_white" 47
BG_MODE24_START "bg_mode24_start" 48 2 set bg color to specified;
3 more params required: r,g,b
valid values: [0-255]
BG_MODE8_START "bg_mode8_start" 48 5 set bg color to specified;
1 more param required: code
valid value: [0-255] (color code)
BG_COLOR_OFF "bg_color_off" 49 reset bg color
high intensity text colors
GRAY "gray" 90
HI_RED "hi_red" 91
HI_GREEN "hi_green" 92
HI_YELLOW "hi_yellow" 93
HI_BLUE "hi_blue" 94
HI_MAGENTA "hi_magenta" 95
HI_CYAN "hi_cyan" 96
HI_WHITE "hi_white" 97
high intensity bg colors
BG_GRAY "bg_gray" 100
BG_HI_RED "bg_hi_red" 101
BG_HI_GREEN "bg_hi_green" 102
BG_HI_YELLOW "bg_hi_yellow" 103
BG_HI_BLUE "bg_hi_blue" 104
BG_HI_MAGENTA "bg_hi_magenta" 105
BG_HI_CYAN "bg_hi_cyan" 106
BG_HI_WHITE "bg_hi_white" 107

SGR formats (click)

References

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

pytermor-1.0.0.tar.gz (13.9 kB view hashes)

Uploaded Source

Built Distribution

pytermor-1.0.0-py3-none-any.whl (10.8 kB view hashes)

Uploaded Python 3

Supported by

AWS AWS Cloud computing and Security Sponsor Datadog Datadog Monitoring Fastly Fastly CDN Google Google Download Analytics Microsoft Microsoft PSF Sponsor Pingdom Pingdom Monitoring Sentry Sentry Error logging StatusPage StatusPage Status page