A Python clone of Foreman for managing Procfile-based applications with process management and export capabilities
—
Handles formatted, colorized output with timestamps, process identification, and cross-platform terminal compatibility. The output formatting system provides consistent, readable output for multi-process applications with proper color support and formatting.
The Printer class handles formatted output with colors, timestamps, and process identification. It provides a consistent interface for displaying process output in a readable format.
class Printer:
"""
Printer defines Honcho's user-visible output. A Printer instance receives
typed messages and prints them to its output in the Honcho format with
timestamps, process names, and optional coloring.
"""
def __init__(self, output=sys.stdout, time_format="%H:%M:%S", width=0, colour=True, prefix=True):
"""
Initialize printer with formatting options.
Parameters:
- output: file-like object for output (default: sys.stdout)
- time_format: str, strftime format for timestamps (default: "%H:%M:%S")
- width: int, minimum width for process names (default: 0, auto-calculated)
- colour: bool, whether to use ANSI color codes (default: True)
- prefix: bool, whether to show timestamp and process name prefix (default: True)
"""
def write(self, message):
"""
Write a formatted message to the output.
Parameters:
- message: Message namedtuple with type, data, time, name, and colour
Raises:
RuntimeError: if message type is not 'line'
"""
# Properties
output: 'TextIO'
time_format: str
width: int
colour: bool
prefix: boolStructured message format for process output with metadata for formatting.
from collections import namedtuple
import datetime
Message = namedtuple("Message", "type data time name colour")Functions for generating ANSI color codes and applying colors to strings with cross-platform compatibility.
def get_colours():
"""
Generator that yields ANSI color codes cyclically for process identification.
Returns:
Generator yielding color code strings in rotation
"""
# ANSI color constants
ANSI_COLOURS = ['grey', 'red', 'green', 'yellow', 'blue', 'magenta', 'cyan', 'white']
# Color code variables (dynamically generated)
grey: str = '30'
red: str = '31'
green: str = '32'
yellow: str = '33'
blue: str = '34'
magenta: str = '35'
cyan: str = '36'
white: str = '37'
# Intense color variants
intense_grey: str = '30;1'
intense_red: str = '31;1'
intense_green: str = '32;1'
intense_yellow: str = '33;1'
intense_blue: str = '34;1'
intense_magenta: str = '35;1'
intense_cyan: str = '36;1'
intense_white: str = '37;1'Utility functions for ANSI color code generation and string formatting.
def _ansi(code):
"""
Generate ANSI escape sequence for given code.
Parameters:
- code: int or str, ANSI color code
Returns:
str: ANSI escape sequence
"""
def _colour_string(colour, s):
"""
Apply color to string using ANSI escape codes.
Parameters:
- colour: str, ANSI color code
- s: str, string to colorize
Returns:
str: colorized string with reset codes
"""import sys
from datetime import datetime
from honcho.printer import Printer, Message
# Create printer with custom formatting
printer = Printer(
output=sys.stdout,
time_format="%H:%M:%S",
width=10,
colour=True,
prefix=True
)
# Create and write messages
message = Message(
type='line',
data='Application starting up...\n',
time=datetime.now(),
name='web',
colour='32' # Green
)
printer.write(message)
# Output: 14:23:45 web | Application starting up...import sys
from datetime import datetime
from honcho.printer import Printer, Message
from honcho.colour import get_colours
# Create printer for multi-process output
printer = Printer(sys.stdout, width=12)
colours = get_colours()
# Simulate output from multiple processes
processes = ['web', 'worker', 'scheduler', 'redis']
for i, process_name in enumerate(processes):
colour = next(colours)
message = Message(
type='line',
data=f'{process_name} process started successfully\n',
time=datetime.now(),
name=process_name,
colour=colour
)
printer.write(message)
# Output:
# 14:23:45 web | web process started successfully
# 14:23:45 worker | worker process started successfully
# 14:23:45 scheduler | scheduler process started successfully
# 14:23:45 redis | redis process started successfullyimport sys
from datetime import datetime
from honcho.printer import Printer, Message
# Create printer with custom time format and no colors
printer = Printer(
output=sys.stdout,
time_format="%Y-%m-%d %H:%M:%S",
colour=False,
prefix=True
)
# Write system message
message = Message(
type='line',
data='System shutting down gracefully\n',
time=datetime.now(),
name='system',
colour=None
)
printer.write(message)
# Output: 2025-01-15 14:23:45 system | System shutting down gracefullyimport sys
from datetime import datetime
from honcho.printer import Printer, Message
# Create printer without prefixes (raw output)
printer = Printer(
output=sys.stdout,
prefix=False
)
# Write raw process output
message = Message(
type='line',
data='This is raw process output\nwith multiple lines\n',
time=datetime.now(),
name='app',
colour=None
)
printer.write(message)
# Output:
# This is raw process output
# with multiple linesfrom datetime import datetime
from honcho.printer import Printer, Message
# Write to file instead of stdout
with open('process.log', 'w') as f:
printer = Printer(
output=f,
colour=False, # No colors in file output
time_format="%Y-%m-%d %H:%M:%S"
)
message = Message(
type='line',
data='Process completed successfully\n',
time=datetime.now(),
name='worker',
colour=None
)
printer.write(message)import sys
from datetime import datetime
from honcho.printer import Printer, Message
printer = Printer(sys.stdout)
# Only 'line' type messages are supported
try:
invalid_message = Message(
type='invalid', # This will cause an error
data='Some data',
time=datetime.now(),
name='test',
colour=None
)
printer.write(invalid_message)
except RuntimeError as e:
print(f"Error: {e}")
# Error: Printer can only process messages of type "line"The output formatting system includes special handling for Windows platforms:
# Windows color support detection
ON_WINDOWS = 'win32' in str(sys.platform).lower()
# Automatic colorama initialization on Windows for ANSI support
try:
import colorama
colorama.init() # Enable ANSI colors on Windows
except ImportError:
# Fall back to no colors if colorama not available
passThe printer automatically detects terminal capabilities and disables colors when output is redirected to files or non-TTY outputs.
Install with Tessl CLI
npx tessl i tessl/pypi-honcho