Skip to main content

A Python library for terminal text colorization and highlighting

Project description

Tinty

The only terminal colorizer with smart color nesting and pipeline composition.

CI codecov PyPI version Python versions Production Ready

Python library and CLI tool for terminal text colorization with automatic priority-based color nesting, pipeline composition, and ANSI-aware pattern matching. Zero dependencies, pure Python.


📖 Quick Navigation


⚡ Quick Start

# Install
pip install tinty

# Smart color nesting - inner groups automatically win
echo "hello world" | tinty '(h.(ll))' red,blue
# Output: "he" is red, "ll" is blue (inner has higher priority)

# Pipeline composition - colors preserved across stages
echo "hello world" | tinty 'hello' red | tinty 'world' blue
# Output: "hello" is red, "world" is blue

# Python API with type-safe constants
from tinty import colored, RED, BLUE, BOLD
print(colored("Error") | RED | BOLD)

🎨 What Makes Tinty Unique

1. 🧠 Smart Color Nesting (No other tool has this!)

Automatic priority-based rendering without manual z-index configuration:

# Nested regex groups - inner automatically wins
echo "hello world" | tinty '(h.(ll))' red,blue
# "he" is red, "ll" is blue (inner group has higher priority)

Priority Rules:

  1. Pipeline stage - Later commands override earlier ones
  2. Nesting depth - Inner regex groups override outer groups
  3. Application order - Later applications win within same depth

2. 🔗 Pipeline Composition

Colors preserved across pipeline stages with intelligent priority:

# Both colors preserved
echo "hello world" | tinty 'hello' red | tinty 'world' blue

# Later stage overrides overlaps
echo "hello world" | tinty 'hello' red | tinty 'llo w' green
# "he" is red, "llo w" is green (overrides)

3. 🎯 Channel Isolation

Foreground, background, and attributes work independently:

# Background + foreground coexist in same text
echo "hello world" | tinty '(h.(ll))' bg_red,blue
# "he" = red background only
# "ll" = red background AND blue foreground (both channels!)

4. 🔍 ANSI-Aware Pattern Matching

Patterns match original text, ignoring existing ANSI codes:

# Works on already-colored text!
colored_text = ColorizedString("H\x1b[31mello\x1b[0m World")
result = colored_text.highlight(r'Hello', ['green'])
# Pattern matches "Hello" despite ANSI codes in the middle

💡 Real-World Examples

Log File Highlighting

from tinty import ColorizedString

log = "ERROR: Connection failed at 10:30:45"
result = (ColorizedString(log)
    .highlight(r'ERROR', ['red', 'bold'])
    .highlight(r'\d{2}:\d{2}:\d{2}', ['blue'])
)
print(result)
# "ERROR" is red+bold, timestamp is blue

Multi-Stage Pipeline Processing

# Stage 1: Highlight errors
cat log.txt | tinty 'ERROR|CRITICAL' red > /tmp/colored.txt

# Stage 2: Add timestamps (higher priority)
cat /tmp/colored.txt | tinty '\d{2}:\d{2}:\d{2}' blue
# Both colors preserved, timestamps override errors if overlapping

Syntax Highlighting

code = "def hello_world():"
result = (ColorizedString(code)
    .highlight(r'\b(def)\b', ['blue'])           # Keywords
    .highlight(r'[a-z_]+\w*(?=\()', ['green'])   # Functions
)
print(result)

🚀 Installation

# From PyPI
pip install tinty

# From source
git clone https://github.com/jim-my/tinty.git
cd tinty
pip install -e .

Requirements:

  • Python 3.9+
  • Zero dependencies (pure Python)

✨ Features

  • 🧠 Smart Color Nesting: Automatic priority-based rendering without manual z-index
  • 🔍 ANSI-Aware Matching: Patterns match original text, ignoring color codes
  • 🎯 Channel Isolation: Foreground, background, and attributes work independently
  • 🔗 Pipeline Composition: Colors preserved across pipeline stages
  • 🔒 Production Safe: No monkey patching or global state pollution
  • 🎭 Multiple APIs: Choose your style - fluent, functional, or global
  • ⚡ High Performance: Efficient implementation with minimal overhead
  • 🧪 Well Tested: 143 tests with comprehensive coverage
  • 📦 Zero Dependencies: Pure Python implementation
  • 🖥️ Cross Platform: Works on Linux, macOS, and Windows

📋 Full Documentation

CLI Usage

Basic Usage

# Simple pattern matching
echo "hello world" | tinty 'l' red

# Pattern groups
echo "hello world" | tinty '(h.*o).*(w.*d)' red blue

Advanced: Nested Colors

# Nested regex groups - inner wins
echo "hello world" | tinty '(h.(ll))' red,blue
# Output: "he" is red, "ll" is blue

# Channel isolation - foreground + background
echo "hello world" | tinty '(h.(ll))' bg_red,blue
# Output: "he" = red bg, "ll" = red bg + blue fg

# Color name formats (both work)
echo "hello" | tinty 'hello' bg_red    # Official format
echo "hello" | tinty 'hello' red_bg    # Natural format (auto-normalized)

CLI Options

# List all available colors
tinty --list-colors

# Case sensitive matching
echo "Hello World" | tinty --case-sensitive 'Hello' green

# Verbose mode (debugging)
echo "test" | tinty --verbose 'test' red

# Clear all previous colors before applying new ones
echo "hello world" | tinty 'hello' red | tinty --replace-all 'world' blue
# Result: Only "world" is blue, "hello" has no color

Python Library API

Type-Safe Constants (Recommended)

from tinty import colored, txt, RED, GREEN, BLUE, YELLOW, BOLD, BG_WHITE, UNDERLINE

# Type-safe constants with operator chaining
print(colored("Success") | GREEN | BOLD)
print(txt("Warning") | YELLOW)
print(colored("Error") | RED | BOLD | BG_WHITE)
print(txt("Info") >> BLUE >> UNDERLINE)

Global Object with Constants

from tinty import C, RED, BOLD

C.red("hello")              # Direct color method
C("hello") | RED | BOLD     # Factory with type-safe constants
C("hello", "red")           # Direct colorization (legacy)

Pattern Highlighting

from tinty import ColorizedString

# Highlight search terms
text = "The quick brown fox jumps over the lazy dog"
highlighted = ColorizedString(text).highlight(
    r"(quick)|(fox)|(lazy)",
    ["red", "blue", "green"]
)
print(highlighted)

# Syntax highlighting
code = "def hello_world():"
result = ColorizedString(code).highlight(r"\b(def)\b", ["blue"])
print(result)

Available Colors and Styles

Foreground Colors

red, green, blue, yellow, magenta, cyan, white, black, lightred, lightgreen, lightblue, lightyellow, lightmagenta, lightcyan, lightgray, darkgray

Background Colors

bg_red, bg_green, bg_blue, bg_yellow, bg_magenta, bg_cyan, bg_white, bg_black, bg_lightred, bg_lightgreen, bg_lightblue, bg_lightyellow, bg_lightmagenta, bg_lightcyan, bg_lightgray, bg_darkgray

Text Styles

bright/bold, dim, underline, blink, invert/swapcolor, hidden, strikethrough

Type-Safe Color Constants

Use constants instead of error-prone string literals:

from tinty import colored, RED, GREEN, BLUE, YELLOW, BOLD, BG_WHITE

# ✅ Type-safe with IDE autocompletion and error checking
error_msg = colored("CRITICAL") | RED | BOLD | BG_WHITE
success_msg = colored("SUCCESS") | GREEN | BOLD
warning_msg = colored("WARNING") | YELLOW

# ❌ Error-prone string literals
error_msg = colored("CRITICAL") | "red" | "typo"  # Runtime error!

Benefits:

  • 🔍 IDE Autocompletion: Get suggestions for valid colors
  • 🛡️ Type Checking: Catch typos at development time
  • 📝 Self-Documenting: Clear, readable code
  • 🔄 Refactoring Safe: Rename constants across codebase
  • No Runtime Errors: Invalid colors caught early

🎨 Advanced: Color Nesting & Priority

Nested Regex Groups

Inner (more specific) capture groups automatically override outer ones:

from tinty import ColorizedString

text = ColorizedString("hello world")

# Pattern: (h.(ll)) creates two groups
# - Group 1: "hell" (outer) → red
# - Group 2: "ll" (inner, higher priority) → blue
result = text.highlight(r'(h.(ll))', ['red', 'blue'])
print(result)
# Output: "he" is red, "ll" is blue (inner wins)

Priority Rules:

  1. Pipeline stage: Later commands override earlier ones
  2. Nesting depth: Inner regex groups override outer groups
  3. Application order: Later applications win within same depth

Channel Isolation

Foreground, background, and attributes are independent channels that can coexist:

text = ColorizedString("hello world")

# Background and foreground don't conflict!
result = text.highlight(r'(h.(ll))', ['bg_red', 'blue'])
print(result)
# Output: "he" has red background
#         "ll" has BOTH red background AND blue foreground

Available Channels:

  • Foreground (fg): Text color (red, blue, green, etc.)
  • Background (bg): Background color (bg_red, bg_blue, etc.)
  • Attributes (attr): Bold, underline, dim, etc.

ANSI-Aware Pattern Matching

Patterns always match the original text, even if it contains ANSI codes:

# Text with existing ANSI codes
colored_text = ColorizedString("H\x1b[31mello\x1b[0m World")

# Pattern still matches "Hello" ignoring the ANSI codes in between
result = colored_text.highlight(r'Hello', ['green'])
print(result)
# Works! Pattern matched the original text "Hello World"

Color Name Flexibility

Both bg_red and red_bg formats are supported:

# These are equivalent:
text.highlight(r'hello', ['bg_red'])    # Official format
text.highlight(r'hello', ['red_bg'])    # Natural format (auto-normalized)

🧪 Development

Running Tests

# Run all tests
pytest

# Run with coverage
pytest --cov=tinty

# Run specific test file
pytest tests/test_nesting.py

Code Quality

# Format and lint
ruff format --preview .
ruff check --preview .

# Type checking
mypy src/

# Run pre-commit hooks
pre-commit run --all-files

📖 Examples

See the examples/ directory for more comprehensive examples:

  • examples/quickstart.py - Basic usage patterns
  • examples/enhanced_demo.py - Full enhanced API demonstration
  • examples/nesting_demo.py - Color nesting and priority examples

🤝 Contributing

Contributions are welcome! See CONTRIBUTING.md for guidelines.

Quick Start:

  1. Fork the repository
  2. Create a feature branch: git checkout -b feature/amazing-feature
  3. Make your changes and add tests
  4. Run tests and pre-commit hooks: pytest && pre-commit run --all-files
  5. Commit your changes: git commit -m "feat: add amazing feature"
  6. Push and create a Pull Request

🗺️ Roadmap

See ROADMAP.md for planned features and future direction.

Upcoming features:

  • Configuration file support (.tintyrc.yaml)
  • Built-in color themes (log-levels, git-diff, python)
  • TrueColor (24-bit RGB) support
  • Pygments integration for syntax highlighting

📄 License

This project is licensed under the MIT License - see the LICENSE file for details.


🙏 Acknowledgments

  • Inspired by the Ruby colorize gem
  • Built with modern Python best practices
  • Designed for production safety and developer experience

🔄 Legacy API (Still Supported)

The original API remains fully supported for backward compatibility:

from tinty import Colorize, ColorizedString

# Original Colorize class
colorizer = Colorize()
print(colorizer.colorize("hello", "red"))

# Original ColorizedString
cs = ColorizedString("hello")
print(cs.colorize("blue"))

📊 Version Management

This project uses automated versioning via git tags:

  • Versions are managed by setuptools-scm based on git tags
  • poetry-dynamic-versioning integrates this with Poetry builds
  • To release: git tag v1.2.3 && git push --tags

Made with ❤️ by the Tinty community

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

tinty-1.2.0.tar.gz (26.1 kB view details)

Uploaded Source

Built Distribution

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

tinty-1.2.0-py3-none-any.whl (22.4 kB view details)

Uploaded Python 3

File details

Details for the file tinty-1.2.0.tar.gz.

File metadata

  • Download URL: tinty-1.2.0.tar.gz
  • Upload date:
  • Size: 26.1 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: poetry/1.8.3 CPython/3.12.10 Darwin/25.0.0

File hashes

Hashes for tinty-1.2.0.tar.gz
Algorithm Hash digest
SHA256 ccc7f01e706767ff6dabf1749c9024bac023aba6de03cd9631f9fe6a3d83f46e
MD5 00d712a06678804c6e2d134cb60606a5
BLAKE2b-256 9f0ba65a088599ae1428e9c39ea04381e525ae473a6a85f9aa0a83b7326fcfe7

See more details on using hashes here.

File details

Details for the file tinty-1.2.0-py3-none-any.whl.

File metadata

  • Download URL: tinty-1.2.0-py3-none-any.whl
  • Upload date:
  • Size: 22.4 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: poetry/1.8.3 CPython/3.12.10 Darwin/25.0.0

File hashes

Hashes for tinty-1.2.0-py3-none-any.whl
Algorithm Hash digest
SHA256 f90fb6cd3d089a3df158547ca29d4ae718606f6a1552e1dd455ebeb6226a8033
MD5 657efa8f1e165ef35fcd8fa4b1a8d714
BLAKE2b-256 a942bd39c1bed58e6540516e1deecc8609322a2dcd6de18870908613b645be70

See more details on using hashes here.

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