Formatters Reference
This document provides a complete reference for all formatters available in ViewText.
Overview
Formatters are functions that transform values into formatted strings for display. They are used in layout definitions to control how field values appear in the output. Unlike computed field operations (which transform data), formatters only affect the presentation.
All formatters are registered in the FormatterRegistry and can be accessed by name in TOML layout configurations.
Common Usage
Formatters are specified in layout line definitions:
[[layouts.my_layout.lines]]
field = "price"
index = 0
formatter = "number"
[layouts.my_layout.lines.formatter_params]
decimals = 2
thousands_sep = ","
prefix = "$"
Built-in Formatters
text
Basic text formatting with optional prefix and suffix.
Parameters:
prefix- String to prepend (optional, default: empty string)suffix- String to append (optional, default: empty string)
Examples:
[[layouts.demo.lines]]
field = "name"
index = 0
formatter = "text"
[layouts.demo.lines.formatter_params]
prefix = "Name: "
suffix = "."
Input: "Alice"
Output: "Name: Alice."
[[layouts.demo.lines]]
field = "status"
index = 1
formatter = "text"
[layouts.demo.lines.formatter_params]
prefix = "["
suffix = "]"
Input: "active"
Output: "[active]"
text_uppercase
Converts text to uppercase.
Parameters:
None
Examples:
[[layouts.demo.lines]]
field = "city"
index = 0
formatter = "text_uppercase"
Input: "san francisco"
Output: "SAN FRANCISCO"
[[layouts.demo.lines]]
field = "code"
index = 1
formatter = "text_uppercase"
Input: "abc123"
Output: "ABC123"
number
Format numbers with precision, separators, and optional prefix/suffix.
Parameters:
decimals- Number of decimal places (optional, default: 0)thousands_sep- Thousands separator character (optional, default: empty string)decimal_sep- Decimal separator character (optional, default: “.”)prefix- String to prepend (optional, default: empty string)suffix- String to append (optional, default: empty string)
Examples:
# Basic number formatting
[[layouts.demo.lines]]
field = "population"
index = 0
formatter = "number"
[layouts.demo.lines.formatter_params]
thousands_sep = ","
Input: 1234567
Output: "1,234,567"
# Temperature with suffix
[[layouts.demo.lines]]
field = "temperature"
index = 1
formatter = "number"
[layouts.demo.lines.formatter_params]
decimals = 1
suffix = "°C"
Input: 23.456
Output: "23.5°C"
# European number format
[[layouts.demo.lines]]
field = "amount"
index = 2
formatter = "number"
[layouts.demo.lines.formatter_params]
decimals = 2
thousands_sep = "."
decimal_sep = ","
Input: 1234567.89
Output: "1.234.567,89"
# With prefix and suffix
[[layouts.demo.lines]]
field = "value"
index = 3
formatter = "number"
[layouts.demo.lines.formatter_params]
decimals = 2
thousands_sep = ","
prefix = "$"
suffix = " USD"
Input: 1234.567
Output: "$1,234.57 USD"
price
Specialized price formatting with currency symbol positioning.
Parameters:
symbol- Currency symbol (optional, default: empty string)symbol_position- “prefix” or “suffix” (optional, default: “prefix”)decimals- Number of decimal places (optional, default: 2)thousands_sep- Thousands separator character (optional, default: empty string)decimal_sep- Decimal separator character (optional, default: “.”)
Examples:
# US Dollar format
[[layouts.demo.lines]]
field = "price"
index = 0
formatter = "price"
[layouts.demo.lines.formatter_params]
symbol = "$"
decimals = 2
thousands_sep = ","
Input: 1234.50
Output: "$1,234.50"
# Euro with suffix
[[layouts.demo.lines]]
field = "price"
index = 1
formatter = "price"
[layouts.demo.lines.formatter_params]
symbol = "€"
symbol_position = "suffix"
decimals = 2
Input: 1234.56
Output: "1234.56€"
# European Euro format
[[layouts.demo.lines]]
field = "price"
index = 2
formatter = "price"
[layouts.demo.lines.formatter_params]
symbol = "€"
decimals = 2
thousands_sep = "."
decimal_sep = ","
Input: 1234567.89
Output: "€1.234.567,89"
# Swiss Franc format
[[layouts.demo.lines]]
field = "amount"
index = 3
formatter = "price"
[layouts.demo.lines.formatter_params]
symbol = "CHF"
symbol_position = "suffix"
decimals = 2
thousands_sep = "'"
Input: 1234567.89
Output: "1'234'567.89CHF"
datetime
Format timestamps and datetime objects using strftime format strings.
Parameters:
format- strftime format string (optional, default: “%Y-%m-%d %H:%M:%S”)
Supported Input Types:
Python datetime objects
Unix timestamps (int or float)
String values (returned as-is)
Examples:
# Full datetime
[[layouts.demo.lines]]
field = "timestamp"
index = 0
formatter = "datetime"
[layouts.demo.lines.formatter_params]
format = "%Y-%m-%d %H:%M:%S"
Input: 1234567890 (Unix timestamp)
Output: "2009-02-13 23:31:30"
# Date only
[[layouts.demo.lines]]
field = "date"
index = 1
formatter = "datetime"
[layouts.demo.lines.formatter_params]
format = "%Y-%m-%d"
Input: datetime(2023, 12, 25, 15, 30)
Output: "2023-12-25"
# Time only
[[layouts.demo.lines]]
field = "time"
index = 2
formatter = "datetime"
[layouts.demo.lines.formatter_params]
format = "%H:%M:%S"
Input: 1703516400
Output: "15:00:00"
# Custom format
[[layouts.demo.lines]]
field = "created_at"
index = 3
formatter = "datetime"
[layouts.demo.lines.formatter_params]
format = "%b %d, %Y at %I:%M %p"
Input: datetime(2023, 12, 25, 15, 30)
Output: "Dec 25, 2023 at 03:30 PM"
Common Format Codes:
%Y- Year with century (e.g., 2023)%m- Month as zero-padded number (01-12)%d- Day of month as zero-padded number (01-31)%H- Hour (24-hour clock) as zero-padded number (00-23)%M- Minute as zero-padded number (00-59)%S- Second as zero-padded number (00-59)%b- Abbreviated month name (Jan, Feb, etc.)%B- Full month name (January, February, etc.)%I- Hour (12-hour clock) as zero-padded number (01-12)%p- AM or PM
relative_time
Format time differences in human-readable relative format (e.g., “5m ago”, “2d ago”).
Parameters:
format- “short” or “long” (optional, default: “short”)
Input:
Time value in seconds (typically the number of seconds elapsed)
Examples:
# Short format
[[layouts.demo.lines]]
field = "elapsed_seconds"
index = 0
formatter = "relative_time"
[layouts.demo.lines.formatter_params]
format = "short"
Input: 45 → Output: "45s ago"
Input: 300 → Output: "5m ago"
Input: 3600 → Output: "1h ago"
Input: 86400 → Output: "1d ago"
# Long format
[[layouts.demo.lines]]
field = "elapsed_seconds"
index = 1
formatter = "relative_time"
[layouts.demo.lines.formatter_params]
format = "long"
Input: 45 → Output: "45 seconds ago"
Input: 300 → Output: "5 minutes ago"
Input: 3600 → Output: "1 hours ago"
Input: 86400 → Output: "1 days ago"
Time Ranges:
Less than 60 seconds: shows seconds
60-3599 seconds: shows minutes
3600-86399 seconds: shows hours
86400+ seconds: shows days
template
Combine multiple fields using a Python format string with field placeholders.
This is the most powerful formatter, allowing you to combine multiple fields with custom formatting specifications in a single template string.
Parameters:
template- Template string with{field}placeholders (required)fields- List of field names/paths to extract from context (required)
Template Features:
Python format specifications (e.g.,
.2f,:>10,:,)Multiple fields in one template
Nested field access via dot notation (e.g.,
current_price.usd)All Python format mini-language features
Examples:
# Basic field combination
[[layouts.demo.lines]]
field = "ticker"
index = 0
formatter = "template"
[layouts.demo.lines.formatter_params]
template = "{symbol} - ${price:.2f}"
fields = ["symbol", "price"]
Input: {"symbol": "BTC", "price": 45234.567}
Output: "BTC - $45234.57"
# Multiple fields with formatting
[[layouts.demo.lines]]
field = "stock"
index = 1
formatter = "template"
[layouts.demo.lines.formatter_params]
template = "{symbol} - ${price:.2f} - {volume}/$"
fields = ["symbol", "price", "volume"]
Input: {"symbol": "AAPL", "price": 172.43, "volume": "1.2M"}
Output: "AAPL - $172.43 - 1.2M/$"
# Nested field access
[[layouts.demo.lines]]
field = "crypto"
index = 2
formatter = "template"
[layouts.demo.lines.formatter_params]
template = "{name}: ${current_price_usd:.2f}"
fields = ["name", "current_price.usd"]
Input: {"name": "Bitcoin", "current_price": {"usd": 45234.567}}
Output: "Bitcoin: $45234.57"
# Answer to user's question: format two floats
[[layouts.demo.lines]]
field = "coordinates"
index = 3
formatter = "template"
[layouts.demo.lines.formatter_params]
template = "{a:.1f} {b:.1f}"
fields = ["a", "b"]
Input: {"a": 3.14159, "b": 2.71828}
Output: "3.1 2.7"
# Alignment and padding
[[layouts.demo.lines]]
field = "table_row"
index = 4
formatter = "template"
[layouts.demo.lines.formatter_params]
template = "{name:<20} {value:>10.2f} {status:^10}"
fields = ["name", "value", "status"]
Input: {"name": "Temperature", "value": 23.456, "status": "OK"}
Output: "Temperature 23.46 OK "
# Thousands separator
[[layouts.demo.lines]]
field = "stats"
index = 5
formatter = "template"
[layouts.demo.lines.formatter_params]
template = "Population: {count:,}"
fields = ["count"]
Input: {"count": 1234567}
Output: "Population: 1,234,567"
# Percentage formatting
[[layouts.demo.lines]]
field = "progress"
index = 6
formatter = "template"
[layouts.demo.lines.formatter_params]
template = "Progress: {value:.1%}"
fields = ["value"]
Input: {"value": 0.756}
Output: "Progress: 75.6%"
Python Format Specification Mini-Language:
The template formatter supports all Python format specifications:
:f- Fixed-point notation:.2f- Fixed-point with 2 decimal places:,- Thousands separator:.2%- Percentage with 2 decimals:>10- Right-align in 10 characters:<10- Left-align in 10 characters:^10- Center in 10 characters:0>5- Zero-pad to 5 characters
See Python’s Format Specification Mini-Language for complete details.
Error Handling:
Missing fields resolve to empty string
Invalid template syntax returns “Template error: <error message>”
Non-dict values are converted to string
Custom Formatters
You can register custom formatters using the FormatterRegistry:
Basic Custom Formatter
from viewtext import get_formatter_registry
def format_percentage(value, **kwargs):
decimals = kwargs.get("decimals", 1)
return f"{value:.{decimals}f}%"
formatter_registry = get_formatter_registry()
formatter_registry.register("percentage", format_percentage)
Then use it in your TOML:
[[layouts.demo.lines]]
field = "growth_rate"
index = 0
formatter = "percentage"
[layouts.demo.lines.formatter_params]
decimals = 2
Advanced Custom Formatter
from viewtext import get_formatter_registry
def format_bytes(value, **kwargs):
"""Format byte count as human-readable size."""
units = ["B", "KB", "MB", "GB", "TB"]
unit_index = 0
size = float(value)
while size >= 1024 and unit_index < len(units) - 1:
size /= 1024
unit_index += 1
decimals = kwargs.get("decimals", 1)
return f"{size:.{decimals}f} {units[unit_index]}"
formatter_registry = get_formatter_registry()
formatter_registry.register("bytes", format_bytes)
Usage:
[[layouts.demo.lines]]
field = "file_size"
index = 0
formatter = "bytes"
[layouts.demo.lines.formatter_params]
decimals = 2
Input: 1536 → Output: "1.50 KB"
Input: 1048576 → Output: "1.00 MB"
Formatter vs Computed Field Operation
It’s important to understand the difference between formatters and computed field operations:
Formatters:
Applied at display time
Only affect presentation, not data
Defined in layout line definitions
Return formatted strings
Cannot be chained or used as input to other fields
Examples: number, price, datetime, template
Computed Field Operations:
Applied at data processing time
Transform the actual data
Defined in the fields section
Return processed values (can be any type)
Can be chained (output of one is input to another)
Examples: add, subtract, multiply, concat, conditional
When to Use Each:
Use formatters when you want to:
Format numbers with thousands separators for display
Add currency symbols to prices
Format dates/times for display
Combine multiple fields into one display string
Use computed field operations when you want to:
Calculate derived values (e.g., subtotal * tax_rate)
Perform unit conversions (e.g., Celsius to Fahrenheit)
Transform data (e.g., concatenate first and last name)
Create intermediate values for further processing
Example showing both:
# Computed field: calculate total price
[fields.total_price]
operation = "multiply"
sources = ["price", "quantity"]
default = 0.0
# Formatter: display total_price with currency symbol
[[layouts.product.lines]]
field = "total_price"
index = 0
formatter = "price"
[layouts.product.lines.formatter_params]
symbol = "$"
decimals = 2
thousands_sep = ","
Formatter Presets
You can define reusable formatter configurations (presets) in your TOML files to promote consistency and reduce duplication across your layouts.
Defining Presets
Formatter presets are defined in the [formatters] section. Each preset has a type
field that specifies the built-in formatter type, along with any parameters for that formatter:
# Define formatter presets
[formatters.usd_price]
type = "price"
symbol = "$"
decimals = 2
thousands_sep = ","
[formatters.eur_price]
type = "price"
symbol = "€"
decimals = 2
thousands_sep = "."
decimal_sep = ","
[formatters.short_date]
type = "datetime"
format = "%Y-%m-%d"
[formatters.time_only]
type = "datetime"
format = "%H:%M"
Using Presets in Layouts
Once defined, presets can be referenced by name in two ways:
Method 1: Direct reference in layout line (recommended for simplicity):
[[layouts.product.lines]]
field = "price"
index = 0
formatter = "usd_price" # References the preset by name
[[layouts.product.lines]]
field = "created_at"
index = 1
formatter = "short_date" # References the preset by name
Method 2: Template field_formatters (useful for template formatter):
[[layouts.crypto.lines]]
field = "ticker"
index = 0
formatter = "template"
[layouts.crypto.lines.formatter_params]
template = "{symbol} - {price}"
fields = ["symbol", "price"]
field_formatters = { "price": "usd_price" } # Apply preset to specific field
Benefits of Using Presets
Consistency - Define formatting rules once, use everywhere
Maintainability - Update formatting in one place, affects all usages
Readability - Layout definitions become more concise and expressive
Reusability - Share formatters across multiple layouts and files
Comparison: Inline vs Preset
Without presets (verbose, repeated configuration):
[[layouts.product.lines]]
field = "price"
index = 0
formatter = "price"
[layouts.product.lines.formatter_params]
symbol = "$"
decimals = 2
thousands_sep = ","
[[layouts.invoice.lines]]
field = "total"
index = 5
formatter = "price"
[layouts.invoice.lines.formatter_params]
symbol = "$"
decimals = 2
thousands_sep = ","
With presets (concise, reusable):
[formatters.usd_price]
type = "price"
symbol = "$"
decimals = 2
thousands_sep = ","
[[layouts.product.lines]]
field = "price"
index = 0
formatter = "usd_price"
[[layouts.invoice.lines]]
field = "total"
index = 5
formatter = "usd_price"
Preset Resolution
When ViewText encounters a formatter name in a layout, it follows this resolution order:
Check if
formatter_paramsis provided inline - use built-in formatter with those paramsCheck if a preset exists with that name - use preset configuration
Fall back to built-in formatter with default parameters
This means you can mix inline parameters and presets in the same layout:
[formatters.standard_date]
type = "datetime"
format = "%Y-%m-%d"
[[layouts.mixed.lines]]
field = "created_at"
index = 0
formatter = "standard_date" # Uses preset
[[layouts.mixed.lines]]
field = "price"
index = 1
formatter = "price"
[layouts.mixed.lines.formatter_params]
symbol = "$"
decimals = 2 # Inline parameters
Organizing Presets in Separate Files
For better organization, you can define formatter presets in a separate file:
formatters.toml:
[formatters.usd_price]
type = "price"
symbol = "$"
decimals = 2
thousands_sep = ","
[formatters.eur_price]
type = "price"
symbol = "€"
decimals = 2
thousands_sep = "."
decimal_sep = ","
layouts.toml:
[layouts.product]
name = "Product Display"
[[layouts.product.lines]]
field = "price"
index = 0
formatter = "usd_price"
Load both files together:
viewtext --config layouts.toml --formatters formatters.toml list
from viewtext import LayoutLoader
loader = LayoutLoader(
config_path="layouts.toml",
formatters_path="formatters.toml"
)
See User Guide for more information on split configuration files.
Best Practices
Use appropriate formatters - Choose the formatter that best matches your data type (price for currency, datetime for timestamps, etc.)
Define global formatter configurations - Create reusable formatter presets for consistency across layouts
Use template formatter for complex formatting - When you need to combine multiple fields or use advanced Python format specifications
Consider localization - Use thousands_sep and decimal_sep parameters to format numbers according to regional conventions
Test with edge cases - Verify formatter behavior with None values, very large/small numbers, and edge cases
Document custom formatters - Add docstrings and examples when creating custom formatters
Keep formatters simple - Formatters should focus on presentation. Use computed field operations for data transformation.
Examples by Use Case
Financial Data
# US stock display
[[layouts.stock.lines]]
field = "ticker"
index = 0
formatter = "template"
[layouts.stock.lines.formatter_params]
template = "{symbol} ${price:.2f} {change:+.2f} ({change_pct:+.1f}%)"
fields = ["symbol", "price", "change", "change_pct"]
# European price formatting
[[layouts.product_eu.lines]]
field = "price"
index = 1
formatter = "price"
[layouts.product_eu.lines.formatter_params]
symbol = "€"
decimals = 2
thousands_sep = "."
decimal_sep = ","
Temperature Display
# Celsius with one decimal
[[layouts.weather.lines]]
field = "temp_celsius"
index = 0
formatter = "number"
[layouts.weather.lines.formatter_params]
decimals = 1
suffix = "°C"
# Both Celsius and Fahrenheit
[[layouts.weather.lines]]
field = "temperature"
index = 1
formatter = "template"
[layouts.weather.lines.formatter_params]
template = "{temp_c:.1f}°C / {temp_f:.1f}°F"
fields = ["temp_c", "temp_f"]
Activity Timestamps
# Last seen time
[[layouts.user.lines]]
field = "last_seen_seconds"
index = 0
formatter = "relative_time"
[layouts.user.lines.formatter_params]
format = "short"
# Created date
[[layouts.user.lines]]
field = "created_at"
index = 1
formatter = "datetime"
[layouts.user.lines.formatter_params]
format = "%b %d, %Y"
Dashboard Layout
# System metrics dashboard
[[layouts.dashboard.lines]]
field = "cpu"
index = 0
formatter = "template"
[layouts.dashboard.lines.formatter_params]
template = "CPU: {usage:>5.1f}% [{cores} cores]"
fields = ["usage", "cores"]
[[layouts.dashboard.lines]]
field = "memory"
index = 1
formatter = "template"
[layouts.dashboard.lines.formatter_params]
template = "MEM: {used:>6.1f}/{total:>6.1f} GB ({pct:>5.1f}%)"
fields = ["used", "total", "pct"]
[[layouts.dashboard.lines]]
field = "uptime"
index = 2
formatter = "relative_time"
[layouts.dashboard.lines.formatter_params]
format = "short"
See Also
Computed Fields Reference - Data transformation operations
User Guide - General usage guide
Examples - Complete example configurations