π¨ Stop Fighting with ANSI Codes
Let's be honest β styling terminal output in Python has always been a bit of a pain:
# The old way π
print('\033[1m\033[91mError:\033[0m \033[4mFile not found\033[0m')
Compare that to this:
# The Vargula way β¨
import vargula as vg
vg.write("<bold><red>Error:</red></bold> <underline>File not found</underline>")
Much better, right? But Vargula goes way beyond just making syntax prettier. It brings color theory, accessibility checking, and professional UI components to your terminal.
π Quick Start
pip install vargula
import vargula as vg
# HTML-like tags for styling
vg.write("This is <red>red</red> and <bold>bold</bold>")
# Hex colors work too
vg.write("Custom <#FF5733>orange</#FF5733> text")
# Background colors with @
vg.write("<@yellow><black>Black on yellow</@yellow></black>")
# Nest as much as you want
vg.write("<bold>Bold with <italic><cyan>italic cyan</cyan></italic></bold>")
π― The Problem It Solves
I built Vargula because I kept running into the same issues:
- Verbose ANSI codes that make code unreadable
- No guidance on creating harmonious color palettes
- Zero accessibility checking β is my output readable for colorblind users?
- Repetitive boilerplate for tables and progress bars
Vargula tackles all of these.
π Built-in Color Theory
Here's where it gets interesting. Need a color palette? Generate one based on actual color theory:
# Generate complementary colors
colors = vg.generate_palette("#3498db", "complementary", 5)
print(vg.preview_palette(colors))
Available schemes:
-
monochromaticβ Single hue variations -
analogousβ Adjacent colors (Β±30Β°) -
complementaryβ Opposite colors (180Β°) -
triadicβ Three evenly spaced (120Β°) -
tetradicβ Four colors in pairs -
split_complementaryβ Softer complementary -
squareβ Four evenly spaced (90Β°)
Create a Complete Theme
# Generate a themed palette
theme = vg.generate_theme_palette("analogous", "#e74c3c")
vg.apply_palette_theme(theme)
# Now use semantic tags
vg.write("<primary>Primary action</primary>")
vg.write("<error>Error message</error>")
vg.write("<success>All good!</success>")
vg.write("<warning>Be careful</warning>")
This automatically creates primary, secondary, accent, success, warning, error, info, and neutral colors based on your chosen scheme.
βΏ Accessibility First
About 8% of men and 0.5% of women have some form of color vision deficiency. Vargula helps you create inclusive terminal apps:
# Check WCAG contrast compliance
ratio = vg.calculate_contrast_ratio("#FFFFFF", "#3498db")
print(f"Contrast ratio: {ratio:.2f}")
# Verify WCAG AA/AAA compliance
if vg.meets_wcag("#FFFFFF", "#000000", "AA"):
print("β Passes WCAG AA")
# Generate accessible themes automatically
theme = vg.generate_accessible_theme(
base_color="#3498db",
background="#ffffff",
wcag_level="AA" # or "AAA"
)
Colorblind Simulation
See how your colors appear to users with different types of color blindness:
colors = ["#FF0000", "#00FF00", "#0000FF"]
# Simulate different types
types = ["protanopia", "deuteranopia", "tritanopia"]
for cb_type in types:
simulated = [vg.simulate_colorblindness(c, cb_type) for c in colors]
print(f"{cb_type}: {simulated}")
# Check if palette is distinguishable
is_safe, problems = vg.validate_colorblind_safety(colors, "deuteranopia")
if not is_safe:
print(f"β Found {len(problems)} problematic color pairs")
π Tables Made Easy
Creating professional tables is trivial:
table = vg.Table(
title="Q4 2024 Sales",
border_style="blue",
box="double",
show_lines=True
)
table.add_column("Region", style="bold", justify="left")
table.add_column("Revenue", style="green", justify="right")
table.add_column("Growth", style="cyan", justify="center")
table.add_row("North", "$1.2M", "+15%")
table.add_row("Europe", "$890K", "+8%")
table.add_row("Asia", "$1.5M", "+22%")
print(table)
Box styles: rounded, square, double, heavy, minimal, none
β±οΈ Progress Bars
Single or multiple progress bars with ETA and rate display:
import time
# Simple progress bar
for item in vg.progress_bar(range(100), desc="Processing"):
time.sleep(0.01)
# Multiple concurrent bars
with vg.MultiProgress() as mp:
download = mp.add_task("Downloading", total=100)
process = mp.add_task("Processing", total=50)
upload = mp.add_task("Uploading", total=80)
# Update independently
for i in range(100):
mp.update(download, 1)
if i % 2 == 0:
mp.update(process, 1)
if i % 3 == 0:
mp.update(upload, 1)
time.sleep(0.02)
π¨ Color Manipulation
Need to adjust colors programmatically?
base = "#3498db"
# Adjust brightness
lighter = vg.lighten(base, 0.2)
darker = vg.darken(base, 0.2)
# Adjust saturation
vivid = vg.saturate(base, 0.3)
muted = vg.desaturate(base, 0.3)
# Rotate hue (color wheel)
shifted = vg.shift_hue("#FF0000", 120) # Red β Green
# Mix colors
purple = vg.mix("#FF0000", "#0000FF", 0.5)
# Invert
inverted = vg.invert("#FF0000") # β #00FFFF
π§ Custom Styles
Define reusable styles once, use them everywhere:
# Create custom styles
vg.create("error", color="red", look="bold")
vg.create("success", color="green", look="bold")
vg.create("debug", color="cyan", look="dim")
# Use them with tags
vg.write("<error>Connection failed</error>")
vg.write("<success>Upload complete</success>")
vg.write("<debug>Debug info here</debug>")
# Temporary styles with context manager
with vg.temporary("temp", color="magenta"):
vg.write("<temp>This style is temporary</temp>")
# Automatically cleaned up
πΎ Save & Load Palettes
Share your color schemes across projects:
# Generate and save
colors = vg.generate_palette("#3498db", "analogous", 5)
vg.save_palette(colors, "ocean_theme.json",
metadata={"name": "Ocean Blue", "author": "Me"})
# Load later
colors, metadata = vg.load_palette("ocean_theme.json")
# Works with themes too
theme = vg.generate_theme_palette("triadic", "#9b59b6")
vg.save_theme(theme, "purple_theme.json")
π₯ Real-World Example: Styled Logger
Let's build a production-ready logger with proper theming:
import vargula as vg
from datetime import datetime
# Setup theme
theme = vg.generate_theme_palette("analogous", "#2196F3")
vg.apply_palette_theme(theme)
# Custom log level styles
vg.create("timestamp", color="#666666")
vg.create("debug", color="cyan", look="dim")
vg.create("info", color="blue")
vg.create("warning", color="yellow", look="bold")
vg.create("error", color="red", look="bold")
vg.create("critical", color="white", bg="red", look="bold")
class Logger:
def log(self, level, message):
ts = datetime.now().strftime("%H:%M:%S")
vg.write(f"<timestamp>[{ts}]</timestamp> <{level}>{level.upper():<8}</{level}> {message}")
def debug(self, msg): self.log("debug", msg)
def info(self, msg): self.log("info", msg)
def warning(self, msg): self.log("warning", msg)
def error(self, msg): self.log("error", msg)
def critical(self, msg): self.log("critical", msg)
# Usage
log = Logger()
log.info("Application started")
log.debug("Loading config from config.json")
log.warning("Cache is 90% full")
log.error("Failed to connect to API")
log.critical("System out of memory!")
π― Advanced Features
Escape Sequences
Need to show literal tags in documentation?
# Use raw strings with backslash
vg.write(r"Use \<red>text\</red> to make text red")
# Or double backslash
vg.write("Tag syntax: \\<bold>...</bold>")
Direct Styling (Without Tags)
# Style text directly
print(vg.style("Error", color="red", look="bold"))
print(vg.style("Custom", color="#FF5733", bg="#1a1a1a"))
print(vg.style("Fancy", color=(255, 87, 51), look=["bold", "underline"]))
Utility Functions
# Strip markup tags
plain = vg.strip("Hello <red>world</red>!") # "Hello world!"
# Remove ANSI codes
styled = vg.style("Text", color="red")
clean = vg.clean(styled) # "Text"
# Get visible length (ignoring ANSI)
styled = vg.style("Hello", color="red")
print(len(styled)) # 18 (includes ANSI)
print(vg.length(styled)) # 5 (visible only)
# Globally enable/disable styling
vg.disable() # No colors
vg.enable() # Colors back
π Tag Syntax Reference
-
<colorname>β Named foreground (e.g.,<red>,<bright_blue>) -
<@colorname>β Named background (e.g.,<@yellow>) -
<#hexcode>β Hex foreground (e.g.,<#FF5733>) -
<@#hexcode>β Hex background (e.g.,<@#FF0000>) -
<lookname>β Text style (e.g.,<bold>,<italic>) -
<customname>β Your custom styles -
\<tag>or\\<tag>β Escape sequences for literal tags
Available colors: black, red, green, yellow, blue, magenta, cyan, white, plus bright_* variants
Available styles: bold, dim, italic, underline, blink, reverse, hidden, strikethrough
π Why Vargula?
For developers who:
- Build CLI tools that need professional output
- Want accessible, inclusive terminal applications
- Need harmonious color schemes without a design degree
- Prefer readable code over ANSI escape sequences
- Value WCAG compliance in terminal UIs
Key advantages:
- β Intuitive HTML-like syntax
- β Color theory algorithms built in
- β WCAG compliance checking
- β Colorblind simulation & validation
- β Professional tables & progress bars
- β Cross-platform (Windows, macOS, Linux)
- β Zero dependencies for core features
π Resources
- GitHub: crystallinecore/vargula
- Docs: vargula.readthedocs.io
-
PyPI:
pip install vargula
π€ Contributing
Contributions are welcome! Check out the GitHub repo to:
- Report bugs
- Request features
- Submit pull requests
- Share your color themes
π¬ Try It Now
import vargula as vg
# Generate a random palette
colors = vg.generate_palette(scheme="triadic", count=5)
# Preview it
print(vg.preview_palette(colors))
# Check accessibility
is_safe, _ = vg.validate_colorblind_safety(colors)
print("β Colorblind-safe!" if is_safe else "β Needs adjustment")
# Create and apply theme
theme = vg.generate_theme_palette("complementary", colors[0])
vg.apply_palette_theme(theme)
# Use semantic colors
vg.write("<primary>Primary</primary>")
vg.write("<error>Error</error>")
vg.write("<success>Success</success>")
What kind of CLI tools are you building? Have you tried Vargula? Drop a comment below! π
Made with π¨ by Sivaprasad Murali
Top comments (0)