Syntax-highlighting, declarative and composable pretty printer for Python 3.5+
—
System for registering custom pretty printers for user-defined types and creating formatted function call representations. This enables extending prettyprinter to handle custom classes and data structures with specialized formatting logic.
Register custom pretty printers for specific types or predicate-based matching, enabling specialized formatting for user-defined classes and data structures.
def register_pretty(type=None, predicate=None):
"""
Decorator that registers a function as the pretty printer for a type.
Parameters:
- type: Type to register for, or string 'module.ClassName' for deferred registration
- predicate: Function taking one argument returning bool for predicate-based matching
Notes:
- Exactly one of 'type' or 'predicate' must be provided
- Decorated function must accept (value, ctx) parameters
- Returns the original function unchanged
Usage:
@register_pretty(MyClass)
def pretty_my_class(value, ctx):
return pretty_call(ctx, MyClass, value.attr1, value.attr2)
"""Check whether a type has a registered pretty printer, useful for conditional formatting logic and debugging registration issues.
def is_registered(type, *, check_superclasses=False, check_deferred=True,
register_deferred=True) -> bool:
"""
Check if a type has a registered pretty printer.
Parameters:
- type: Type to check for registration
- check_superclasses (bool): Check superclass types (default: False)
- check_deferred (bool): Check deferred registrations (default: True)
- register_deferred (bool): Register deferred printers when found (default: True)
Returns:
- bool: True if type has registered pretty printer
Raises:
- ValueError: If register_deferred=True when check_deferred=False
"""Create formatted function call representations with automatic argument handling and keyword argument preservation.
def pretty_call(ctx, fn, *args, **kwargs):
"""
Create a Doc representing a function call with arguments.
Parameters:
- ctx (PrettyContext): Current pretty printing context
- fn: Callable to represent in the call
- args: Positional arguments for the call
- kwargs: Keyword arguments for the call
Returns:
- Doc: Document representing the formatted function call
Notes:
- Requires Python 3.6+ for keyword argument order preservation
- Automatically handles syntax highlighting and layout
- For Python 3.5 compatibility, use pretty_call_alt instead
"""Create formatted function call representations with explicit argument specification, compatible with all Python versions.
def pretty_call_alt(ctx, fn, args=(), kwargs=()):
"""
Create a Doc representing a function call with explicit arguments.
Parameters:
- ctx (PrettyContext): Current pretty printing context
- fn: Callable to represent in the call
- args (tuple): Tuple of positional arguments
- kwargs: OrderedDict, dict, or iterable of (key, value) pairs for keyword arguments
Returns:
- Doc: Document representing the formatted function call
Notes:
- Works on all Python versions including 3.5
- For consistent results on Python 3.5, use OrderedDict or list of tuples for kwargs
"""from prettyprinter import register_pretty, pretty_call
from collections import namedtuple
# Custom class example
class Person:
def __init__(self, name, age, email):
self.name = name
self.age = age
self.email = email
@register_pretty(Person)
def pretty_person(person, ctx):
return pretty_call(ctx, Person, person.name, person.age, person.email)
# Now Person instances are pretty printed as constructor calls
person = Person("Alice", 30, "alice@example.com")
pprint(person)
# Output: Person('Alice', 30, 'alice@example.com')from prettyprinter import register_pretty, pretty_call, comment
import datetime
class Task:
def __init__(self, title, priority=1, due_date=None, completed=False):
self.title = title
self.priority = priority
self.due_date = due_date
self.completed = completed
@register_pretty(Task)
def pretty_task(task, ctx):
# Show different representation based on completion status
if task.completed:
return comment(
pretty_call(ctx, Task, task.title,
priority=task.priority,
due_date=task.due_date,
completed=task.completed),
'COMPLETED'
)
else:
return pretty_call(ctx, Task, task.title,
priority=task.priority,
due_date=task.due_date)
# Usage
task1 = Task("Write documentation", priority=2,
due_date=datetime.date(2024, 1, 15))
task2 = Task("Review code", completed=True)
pprint([task1, task2])from prettyprinter import register_pretty
from collections.abc import Mapping
# Register pretty printer for all custom mapping types
@register_pretty(predicate=lambda obj: isinstance(obj, Mapping) and
type(obj).__name__.endswith('Dict'))
def pretty_custom_dicts(mapping, ctx):
return pretty_call(ctx, type(mapping), dict(mapping))
# This will handle CustomDict, OrderedDict, etc.
class CustomDict(dict):
pass
custom = CustomDict([('a', 1), ('b', 2)])
pprint(custom) # CustomDict({'a': 1, 'b': 2})from prettyprinter import register_pretty
# Register for a type that might not be imported yet
@register_pretty('numpy.ndarray')
def pretty_numpy_array(arr, ctx):
# This registration is deferred until numpy.ndarray is actually encountered
return pretty_call(ctx, type(arr), arr.tolist())
# The registration becomes active when numpy arrays are first encountered
import numpy as np
arr = np.array([1, 2, 3, 4, 5])
pprint(arr) # Triggers registration and uses custom formatterfrom prettyprinter import register_pretty, pretty_call
class Database:
def __init__(self, name, tables=None):
self.name = name
self.tables = tables or []
class Table:
def __init__(self, name, columns=None, rows=0):
self.name = name
self.columns = columns or []
self.rows = rows
@register_pretty(Database)
def pretty_database(db, ctx):
return pretty_call(ctx, Database, db.name, tables=db.tables)
@register_pretty(Table)
def pretty_table(table, ctx):
return pretty_call(ctx, Table, table.name,
columns=table.columns, rows=table.rows)
# Nested objects are automatically handled
db = Database("myapp", [
Table("users", ["id", "name", "email"], 1000),
Table("posts", ["id", "title", "content"], 5000)
])
pprint(db)
# Output shows nested structure with custom formatting for both typesfrom prettyprinter import is_registered, register_pretty
class MyClass:
pass
# Check if registered
print(is_registered(MyClass)) # False
@register_pretty(MyClass)
def pretty_my_class(obj, ctx):
return "MyClass()"
# Now it's registered
print(is_registered(MyClass)) # True
# Check superclasses too
class MySubClass(MyClass):
pass
print(is_registered(MySubClass)) # False
print(is_registered(MySubClass, check_superclasses=True)) # Truefrom prettyprinter import register_pretty, pretty_call_alt
from collections import OrderedDict
@register_pretty(Person)
def pretty_person_alt(person, ctx):
# Use explicit args and kwargs for Python 3.5 compatibility
return pretty_call_alt(
ctx,
Person,
args=(person.name,),
kwargs=OrderedDict([
('age', person.age),
('email', person.email)
])
)Install with Tessl CLI
npx tessl i tessl/pypi-prettyprinter