Skip to content

pprint and pformat¤

This wadler_lindig library offers two main functions: wadler_lindig.pprint and wadler_lindig.pformat. The first pretty-prints a Python object to stdout, and the second returns a string representation.

By default it understands a wide variety of Python types.

Let's take a look:

import dataclasses

import wadler_lindig as wl


@dataclasses.dataclass
class Point:
    x: int
    y: int
    z: int


@dataclasses.dataclass
class Mesh:
    points: list[Point]


origin = Point(0, 0, 0)
vertex1 = Point(1, 0, 0)
vertex2 = Point(0, 1, 0)
vertex3 = Point(0, 0, 1)
simplex = Mesh([origin, vertex1, vertex2, vertex3])

# Look at that beautiful formatting and indentation:
wl.pprint(simplex)
Mesh(
  points=[
    Point(x=0, y=0, z=0),
    Point(x=1, y=0, z=0),
    Point(x=0, y=1, z=0),
    Point(x=0, y=0, z=1)
  ]
)

We can also return a string, rather than printing directly to stdout:

wl.pformat(simplex)
'Mesh(\n  points=[\n    Point(x=0, y=0, z=0),\n    Point(x=1, y=0, z=0),\n    Point(x=0, y=1, z=0),\n    Point(x=0, y=0, z=1)\n  ]\n)'

Setting width, indents, and arrays¤

We can customise the indent:

wl.pprint(simplex, indent=4)
Mesh(
    points=[
        Point(x=0, y=0, z=0),
        Point(x=1, y=0, z=0),
        Point(x=0, y=1, z=0),
        Point(x=0, y=0, z=1)
    ]
)

And the width:

wl.pprint(simplex, width=100)
Mesh(
  points=[Point(x=0, y=0, z=0), Point(x=1, y=0, z=0), Point(x=0, y=1, z=0), Point(x=0, y=0, z=1)]
)
wl.pprint(simplex, width=15)
Mesh(
  points=[
    Point(
      x=0,
      y=0,
      z=0
    ),
    Point(
      x=1,
      y=0,
      z=0
    ),
    Point(
      x=0,
      y=1,
      z=0
    ),
    Point(
      x=0,
      y=0,
      z=1
    )
  ]
)

If we have numpy (or PyTorch or JAX) arrays, then we can toggle whether to display them in short form...

import numpy as np


x = np.arange(24.0).reshape(2, 3, 4)
wl.pprint(x, short_arrays=True)  # default value for `short_array`
f64[2,3,4](numpy)

or long form:

wl.pprint(x, short_arrays=False)  # use the normal repr for the array
array([[[ 0.,  1.,  2.,  3.],
        [ 4.,  5.,  6.,  7.],
        [ 8.,  9., 10., 11.]],

       [[12., 13., 14., 15.],
        [16., 17., 18., 19.],
        [20., 21., 22., 23.]]])

Handling custom types¤

Finally, if we have a custom type for which we want to override its pretty representation, then we can either use the custom argument:

class Foo:
    pass


def custom(obj):
    if isinstance(obj, Foo):
        return wl.TextDoc("Bar")
    else:
        return None


wl.pprint(Foo(), custom=custom)
Bar

Or we can set the object's __pdoc__ method:

class Foo:
    def __pdoc__(self, **kwargs) -> None | wl.AbstractDoc:
        return wl.TextDoc("Bar")

Being able to define useful well-formatted reprs for your custom complicated types is actually one of the major use-cases for the wadler_lindig library! For this reason we have a dedicated collection of tutorial on how this works: see how the WL algorithm works.