Skip to main content

A library for string color styling using ANSI escape sequences.

Project description

pyansistring

pyansistring Banner

CI Build codecov PyPI - Version PyPI - Python Version License: MIT Ruff

About The Project

pyansistring is a library for string color styling using ANSI escape sequences. The base class inherits from Python's str. You can split, join, or slice the string while preserving the styling.

Features

  • Preservation of the str methods.
  • Support for 4-, 8-, and 24-bit (True Color) color modes.
  • Per-word coloring.
  • Left, right, and center alignment without problems caused by string length.
  • Support for multiple SGR (Select Graphic Rendition) parameters.
  • Support for both the traditional ";" and the modern ":" SGR parameter separators.
  • Automated coloring functionality, e.g., rainbow text.

For a more comprehensive list of what's been done so far, see the TODO section.

Inspired by rich and colorama Python libraries.

Getting Started

Prerequisites

Installation

You can install the package via pip:

pip install pyansistring # or pip3 install pyansistring
pip install pyansistring[svg] # for SVG conversion support

Or locally via git:

  1. Clone the repository
    git clone https://github.com/l1asis/pyansistring
    
  2. Navigate to the cloned directory
    cd pyansistring
    
  3. Change git remote url to avoid accidental pushes to base project
    git remote set-url origin github_username/repo_name
    # Verify the changes
    git remote -v
    
  4. (Optional) Create and activate a virtual environment
    python -m venv venv
    # On Windows
    .\venv\Scripts\activate
    # On Unix or MacOS
    source venv/bin/activate
    
  5. Install the package
    pip install .
    pip install .[svg] # for SVG conversion support
    

(back to top)

Usage

Import the necessary classes and initialize an ANSIString instance:

from pyansistring.pyansistring import ANSIString
from pyansistring.constants import SGR, Foreground, Background, UnderlineMode

Unstyled plain string:

text = ANSIString("Hello, World!")
print(text)

Result: unstyled plain string in black

Style the whole string:

print(
    ANSIString("Hello, World!")
        .fg_4b(Foreground.YELLOW)
        .bg_4b(Background.BLUE)
        .fm(SGR.BOLD)
)

Result: string with yellow foreground, blue background, and bold styling

Style by slice (indices are [start, end, step]):

print(
    ANSIString("Hello, World!")
        .fg_4b(Foreground.YELLOW, (0, 5), (7, 12))  # "Hello" and "World"
        .bg_4b(Background.BLUE, (7, 12))            # "World"
        .fm(SGR.BOLD, (7, 12))                      # "World"
)

Result: string where "Hello" and "World" have a yellow foreground. "World" also has a blue background and is in bold.

Style by words:

print(
    ANSIString("Hello, World!")
        .fg_4b_w(Foreground.YELLOW, "Hello", "World")
        .bg_4b_w(Background.BLUE, "World")
        .fm_w(SGR.BOLD, "Hello", "World")
)

Result: string where "Hello" and "World" have a yellow foreground and bold styling. "World" also has a blue background.

SGR parameters like bold and underline:

print(
    ANSIString("Hello, World!")
        .fm(SGR.BOLD)
        .fm(SGR.UNDERLINE)
)

Result: bold and single underlined string

4-bit examples (doesn't exist for underline):

print(
    ANSIString("Hello, World!")
        .fg_4b(Foreground.YELLOW)
        .bg_4b(Background.BLUE)
)

Result: string with yellow foreground and blue background

8-bit examples:

print(
    ANSIString("Hello, World!")
        .fg_8b(11)  # Bright Yellow
        .bg_8b(4)   # Blue
        .ul_8b(74)  # Muted Sky Blue
)

Result: string with bright yellow foreground, blue background, and muted sky blue underline

24-bit (True Color) example:

print(
    ANSIString("Hello, World!")
        .fg_24b(255, 255, 0)    # Bright Yellow
        .bg_24b(0, 0, 238)      # Blue
        .ul_24b(135, 175, 215)  # Light Steel Blue
)

Result: string with bright yellow foreground, blue background, and light steel blue underline

Underline modes (not "styles" to avoid confusion with other styling):

print(
    ANSIString("Hello, World!")
        .bg_24b(255, 255, 255)  # White
        .ul_24b(255, 0, 0)      # Red
        .fm(UnderlineMode.DOUBLE)
)

Result: string with white background and red double underline

Lengths and plain text:

styled = ANSIString("Hello, World!").fg_4b(Foreground.MAGENTA)

print(len(styled) == len("Hello, World!"))
# True (logical length ignores ANSI)
print(len(styled.styled_text) == len("Hello, World!"))
# False (includes ANSI codes)
print(styled.actual_length == len("Hello, World!"))
# False (includes ANSI codes)
print(styled.plain)
# "Hello, World!"

ANSIString conversion to SVG text:

from fontTools.ttLib import TTFont

styled = ANSIString("Hello, World!").fg_4b(Foreground.MAGENTA)
styled.to_svg(
    font=TTFont("path/to/font.ttf"),
    font_size_px=16,
    output_file="hello_world.svg"
)

ANSIString conversion to SVG path (for better compatibility when font is not guaranteed to be present):

from fontTools.ttLib import TTFont

styled = ANSIString("Hello, World!").fg_4b(Foreground.MAGENTA)
styled.to_svg(
    font=TTFont("path/to/font.ttf"),
    font_size_px=16,
    convert_text_to_path=True,
    output_file="hello_world_path.svg"
)

[!NOTE] Please note that when convert_text_to_path is set to True, the characters will be converted into vector shapes, which can help ensure that the appearance of the text remains consistent across different platforms and devices, even if the specified font is not available. However, this also means that the text will no longer be selectable or searchable in the SVG file, as it will be treated as graphical elements rather than text. Neither will it be 100% identical to how it looks in the terminal or being rendered as text in the SVG.

[!WARNING] Supported SGR parameters for SVG conversion include:

  • Foreground and background colors (4-bit, 8-bit, and 24-bit)
  • Underline colors with all modes (single, double, curly, dotted, dashed)
  • Bold and italic font styles Unsupported SGR parameters (e.g., strikethrough, inverse, etc.) will be ignored during SVG conversion.

Rainbow text as a separate function:

print(
    ANSIString("Hello, World! This is rainbow text!")
        .rainbow(fg=True)
)

Result: rainbow text with automatic transition

Colored text using multicolor functionality:

print(
    ANSIString("Hello, World! This is multicolor text!")
        .multicolor((
            "r=0:|g=0:|b=255:   $ "  # Start with blue
            "b>0:repeat(auto)   # "  # Decrease blue
            "r>255:repeat(auto) | "  # Increase green and combine with...
            "g>255:repeat(auto)   "  # Increase red
            "                   &*"  # Cycle & Start without apply flags
        ))
)

Result: multicolor text with a transition effect from blue to yellow

For more examples, see the examples directory.

(back to top)

Contributing

Contributions are what make the open source community such an amazing place to learn, inspire, and create. Any contributions you make are greatly appreciated.

If you have a suggestion that would make this better, please fork the repo and create a pull request. You can also simply open an issue with the tag "enhancement". Don't forget to give the project a star! Thanks again!

  1. Fork the Project
  2. Create your Feature Branch (git checkout -b feature/AmazingFeature)
  3. Commit your Changes (git commit -m 'Add some AmazingFeature')
  4. Push to the Branch (git push origin feature/AmazingFeature)
  5. Open a Pull Request

P.S. I would love to see your arts made with pyansistring in the arts.py file, with proper attribution, of course!

(back to top)

License

Distributed under the MIT License. See LICENSE for more information.

(back to top)

Acknowledgements

(back to top)

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

pyansistring-0.2.0.tar.gz (128.3 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

pyansistring-0.2.0-py3-none-any.whl (56.8 kB view details)

Uploaded Python 3

File details

Details for the file pyansistring-0.2.0.tar.gz.

File metadata

  • Download URL: pyansistring-0.2.0.tar.gz
  • Upload date:
  • Size: 128.3 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.7

File hashes

Hashes for pyansistring-0.2.0.tar.gz
Algorithm Hash digest
SHA256 de2bc921bc4b3902a1b58f7189923d7f97c157bd8f3d9a2c69e4b94734d77e94
MD5 50499f31b72f276c9a10ba718b541877
BLAKE2b-256 35508234512fe1cb4c240af48e09c488372e6385cfc0c43d4dbf29451211de09

See more details on using hashes here.

Provenance

The following attestation bundles were made for pyansistring-0.2.0.tar.gz:

Publisher: publish-to-pypi.yml on l1asis/pyansistring

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file pyansistring-0.2.0-py3-none-any.whl.

File metadata

  • Download URL: pyansistring-0.2.0-py3-none-any.whl
  • Upload date:
  • Size: 56.8 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.7

File hashes

Hashes for pyansistring-0.2.0-py3-none-any.whl
Algorithm Hash digest
SHA256 d8361e28992d8d96ff71302f6cef7637c3e446a15776e62c3dddddbb91f5b9af
MD5 68edcad07284340dc60d365a18ad3c6e
BLAKE2b-256 bf390ea2dbe129317a2d2dda4a8ef02ddaaea8b973a51a0d32bb8fb36cb7c32e

See more details on using hashes here.

Provenance

The following attestation bundles were made for pyansistring-0.2.0-py3-none-any.whl:

Publisher: publish-to-pypi.yml on l1asis/pyansistring

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Supported by

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