Skip to content

API¤

Pretty printing¤

The main two functions are wadler_lindig.pprint and wadler_lindig.pformat, to pretty-print (to stdout) or pretty-format (return a string) any Python object.

wadler_lindig.pprint(obj: Any, *, width: int = 88, indent: int = 2, short_arrays: bool = True, custom: Callable[[Any], None | AbstractDoc] = <function _none>, hide_defaults: bool = True, seen_ids: None | set[int] = None, **kwargs) -> None ¤

Pretty-prints an object to stdout.

Arguments:

  • obj: the object to pretty-print.
  • width: a best-effort maximum width to allow. May be exceeded if there are unbroken pieces of text which are wider than this.
  • indent: when the contents of a structured type are too large to fit on one line, they will be indented by this amount and placed on separate lines.
  • short_arrays: whether to print a NumPy array / PyTorch tensor / JAX array as a short summary of the form f32[3,4] (here indicating a float32 matrix of shape (3, 4))
  • custom: a way to pretty-print custom types. This will be called on every object it . If its return is None then the default behaviour will be performed. If its return is an wadler_lindig.AbstractDoc then that will be used instead.
  • hide_defaults: whether to show the default values of dataclass fields.
  • seen_ids: the id(...) of any Python objects that have already been seen, and should not be further introspected to avoid recursion errors (e.g. x = []; x.append(x)). Note that for efficiency, this argument will be mutated with the ids encountered.
  • **kwargs: all other unrecognized kwargs are forwarded on to any __pdoc__ methods encountered, as an escape hatch for custom behaviour.

Returns:

A string representing obj.

Info

The behaviour of this function can be customised in two ways.

First, any object which implements a __pdoc__(self, **kwargs) -> None | AbstractDoc method will have that method called to determine its pretty-doc.

Second, the custom argument to this function can be used. This is particularly useful to provide custom pretty-docs for objects provided by third-party libraries. (For which you cannot add a __pdoc__ method.)

wadler_lindig.pformat(obj: Any, *, width: int = 88, indent: int = 2, short_arrays: bool = True, custom: Callable[[Any], None | AbstractDoc] = <function _none>, hide_defaults: bool = True, **kwargs) -> str ¤

As wadler_lindig.pprint, but returns a string instead of printing to stdout.

Pretty diffs¤

As a utility we offer wadler_lindig.pdiff as a quick way to diff two strings. This is a thin wrapper around the Python built-in library difflib.

wadler_lindig.pdiff(minus: str, plus: str) -> str ¤

Returns a pretty-diff between two strings.

(This is just a thin wrapper around the builtin difflib, and is just here as a helper for common use-cases.)

Example

minus = "hello\nthere\nobi wan kenobi"
plus = "hello\nthere\npatrick kidger"
print(wadler_lindig.pdiff(minus, plus))
#   hello
#   there
# - obi wan kenobi
# + patrick kidger

Arguments:

  • minus: any lines unique to this string will be prefixed with a -.
  • plus: any lines unique to this string will be prefixed with a +.

Returns:

A diff between the two tsrings minus and plus, showing their shared lines once and the unique lines from each.

Colours and ANSI escape codes¤

As a utility we offer some support for adding colours via ANSI escape codes, or to remove all ANSI escape codes from a string.

wadler_lindig.ansi_format(text: str, fg_colour: str, bold: bool) -> str ¤

Formats text with a foreground colour fg_colour, and optionally mark it bold, using ANSI colour codes.

wadler_lindig.ansi_strip(text: str) -> str ¤

Removes all ANSI codes from a string.

Wadler–Lindig documents¤

wadler_lindig.AbstractDoc ¤

Base class for all document types.

For more on the following shorthand methods, see the methods example.

__add__(self, other: AbstractDoc) -> ConcatDoc ¤

doc1 + doc2 offers a convenient shorthand for ConcatDoc(doc1, doc2).

nest(self, indent: int) -> NestDoc ¤

doc.nest(indent) offers a convenient shorthand for NestDoc(doc, indent).

group(self) -> GroupDoc ¤

doc.group() offers a convenient shorthand for GroupDoc(doc).

wadler_lindig.BreakDoc (AbstractDoc) ¤

If in vertical mode then this is a valid place to insert a newline. If in horizontal mode then self.text will be displayed instead.

__init__(self, text: str) ¤

Arguments:

  • text: the string of text to display if a newline is not inserted. Common values are " " (for example between elements of a list) or "" (for example between the final element of a list and a closing ']').

wadler_lindig.ConcatDoc (AbstractDoc) ¤

Concatenate multiple documents together, to be displayed one after another.

If for example these consist only of TextDocs and other ConcatDocs then there is no implied breaking between them, so the formatted text may exceed the maximum width. You may wish to separate pieces with BreakDocs to indicate this, for example.

__init__(self, *args, *, children = None) ¤

Arguments:

Can be called as any of:

  • ConcatDoc(doc1, doc2, doc3, ...)
  • ConcatDoc(children=(doc1, doc2, doc3, ...))
  • doc1 + doc2 + doc3 + ...

wadler_lindig.GroupDoc (AbstractDoc) ¤

Groups the parts of a child document to be laid out all horizontally together or all vertically together.

This decision will persist everywhere outside any child GroupDocs, within which their own local rule is used. For example using [...] to denote a grouping:

[
    foo,
    bar,
    [baz, qux]
]
then foo, bar and [baz, qux] are laid out vertically, but the sub-group [baz, qux] is judged to have enough space, and so is laid out horizontally.

__init__(self, child: AbstractDoc) ¤

Arguments:

  • child: the child document to display.

wadler_lindig.NestDoc (AbstractDoc) ¤

If in vertical mode, increase the indent after each newline by indent whilst displaying child.

__init__(self, child: AbstractDoc, indent: int) ¤

Arguments:

  • child: the child document to display.
  • indent: how much to increase the indent.

Frequently child will be ConcatDoc(BreakDoc(""), another_doc), so that the first line of another_doc will be indented as much as its later lines. See also the The (break-group).nest-break example.

wadler_lindig.TextDoc (AbstractDoc) ¤

Represents an unbroken piece of text to display. May include newlines.

__init__(self, text: str) ¤

Arguments:

  • text: the string of text.

wadler_lindig.pdoc(obj: Any, indent: int = 2, short_arrays: bool = True, custom: Callable[[Any], None | AbstractDoc] = <function _none>, hide_defaults: bool = True, seen_ids: None | set[int] = None, **kwargs) -> AbstractDoc ¤

Formats an object into a Wadler–Lindig document. Such documents are essentially strings that haven't yet been pretty-formatted to a particular width.

Arguments:

  • obj: the object to pretty-doc.
  • indent: when the contents of a structured type are too large to fit on one line, they will be indented by this amount and placed on separate lines.
  • short_arrays: whether to print a NumPy array / PyTorch tensor / JAX array as a short summary of the form f32[3,4] (here indicating a float32 matrix of shape (3, 4))
  • custom: a way to pretty-doc custom types. This will be called on every object it encounters. If its return is None then the usual behaviour will be performed. If its return is an AbstractDoc then that will be used instead.
  • hide_defaults: whether to show the default values of dataclass fields.
  • seen_ids: the id(...) of any Python objects that have already been seen, and should not be further introspected to avoid recursion errors (e.g. x = []; x.append(x)). Note that for efficiency, this argument will be mutated with the ids encountered.
  • **kwargs: all kwargs are forwarded on to all __pdoc__ calls, as an escape hatch for custom behaviour.

Returns:

A pretty-doc representing obj.

Info

The behaviour of this function can be customised in two ways.

First, any object which implements a __pdoc__(self, **kwargs) -> None | AbstractDoc method will have that method called to determine its pretty-doc.

Second, the custom argument to this function can be used. This is particularly useful to provide custom pretty-docs for objects provided by third-party libraries. (For which you cannot add a __pdoc__ method yourself.)

Utilities¤

wadler_lindig.array_summary(shape: tuple[int, ...], dtype: str, kind: None | str) -> TextDoc ¤

Summarises an array based on its shape/dtype/kind. (Where 'kind' refers to NumPy vs PyTorch vs JAX etc.)

Arguments:

  • shape: a tuple of integers.
  • dtype: a string, for which common dtypes will be contracted (float -> f, uint -> u, int -> i, complex -> c)
  • kind: optional. If provided it is written in brackets afterwards.

Returns:

A wadler_lindig.TextDoc with text looking like e.g. f32[2,3,4](numpy) for a NumPy array of shape (2, 3, 4) and float32 dtype.

wadler_lindig.bracketed(begin: AbstractDoc, docs: Sequence[AbstractDoc], sep: AbstractDoc, end: AbstractDoc, indent: int) -> AbstractDoc ¤

A helper for formatting a 'bracketed' object: tuples, lists, classes, etc, which are all represented in essentially similar ways: a pair of brackets (whether round, square, etc.), a sequence of values in between -- which are indented if laid out in vertical mode, and possibly a name as prefix.

See the (break-group).nest-break example for more on the pattern that this enables.

Arguments:

  • begin: appears at the start, before any indent.
  • docs:: a sequence of documents. They will either be laid out horizontally together or vertically together.
  • sep: each element of docs will be separated by sep.
  • end: appears at the end, after any indent.
  • indent: how much to indent (for wadler_lindig.NestDoc to use) when laying out vertically.

Returns:

A document in (break-group).nest-break form.

Example

Formatting a list, which do not have any name prefix:

import wadler_lindig as wl

wl.bracketed(
    begin=wl.TextDoc("["),
    docs=[wl.pdoc(x) for x in obj],
    sep=wl.comma,
    end=wl.TextDoc("]"),
    indent=indent,
)

Formatting a frozenset, which does have a name prefix:

import wadler_lindig as wl

wl.bracketed(
    begin=wl.TextDoc("frozenset({"),
    docs=[wl.pdoc(x) for x in obj],
    sep=wl.comma,
    end=wl.TextDoc("})"),
    indent=indent,
)

wadler_lindig.comma ¤

A shorthand for TextDoc(',') + BreakDoc(' ').

wadler_lindig.join(sep: AbstractDoc, docs: Sequence[AbstractDoc]) -> AbstractDoc ¤

Concatenates objs together separated by sep.

Arguments:

  • sep: the separate to use.
  • docs: a sequence of documents to join.

Returns:

ConcatDoc(docs[0], sep, docs[1], sep, docs[2], ..., sep, docs[-1])

wadler_lindig.named_objs(pairs: Iterable[tuple[str, Any]], **kwargs) -> list[AbstractDoc] ¤

Formats key-value pairs in the form 'key=value'.

Arguments:

  • pairs: an iterable of (key, value) pairs.
  • **kwargs: passed on to each pdoc(value, **kwargs)

Returns:

A list of documents TextDoc(key) + TextDoc("=") + pdoc(value, **kwargs) for each key-value pair.