The __pdoc__
method¤
The general pattern is the following:
class MyAmazingClass:
def __pdoc__(self, **kwargs) -> wadler_lindig.AbstractDoc:
... # Create your pretty representation here!
def __repr__(self):
# Calls `__pdoc__` and then formats to a particular width.
return wadler_lindig.pformat(self, width=80)
Let's go ahead and create such an example now! Let's build an example involving mathematical expressions.
import wadler_lindig as wl
class AbstractExpression:
def __repr__(self):
return wl.pformat(self, width=80)
def __add__(self, other):
return BinaryOperation("+", self, other)
class Symbol(AbstractExpression):
def __init__(self, name: str):
self.name = name
def __call__(self, *args):
return FunctionCall(self.name, *args)
def __pdoc__(self, **kwargs):
return wl.TextDoc(wl.ansi_format(self.name, "red", bold=False))
class BinaryOperation(AbstractExpression):
def __init__(self, op: str, left: AbstractExpression, right: AbstractExpression):
self.op = op
self.left = left
self.right = right
def __pdoc__(self, **kwargs):
left = wl.pdoc(self.left)
brk = wl.BreakDoc(" ")
op = wl.TextDoc(self.op)
right = wl.pdoc(self.right)
return wl.ConcatDoc(left, brk, op, wl.TextDoc(" "), right)
class FunctionCall(AbstractExpression):
def __init__(self, fn: str, *args: AbstractExpression):
self.fn = fn
self.args = args
def __pdoc__(self, **kwargs):
fn = wl.TextDoc(wl.ansi_format(self.fn, "blue", bold=True))
brk = wl.BreakDoc("")
args = [wl.pdoc(arg) for arg in self.args]
args = wl.join(wl.comma, args)
args = wl.NestDoc(wl.ConcatDoc(brk, wl.GroupDoc(args)), indent=kwargs["indent"])
return wl.ConcatDoc(fn, wl.TextDoc("("), args, brk, wl.TextDoc(")"))
f = Symbol("amazing_fn")
x = Symbol("arg0")
y = Symbol("arg1")
z = Symbol("arg2")
w = Symbol("arg3")
expr = f(x, y, z + w)
Now let's pretty-print the result:
wl.pprint(expr, width=50)
wl.pprint(expr, width=30)
wl.pprint(expr, width=20)
wl.pprint(expr, width=10)
And because we defined our __repr__
in terms of pretty-printing, then this works too:
print(repr(expr))
This is one of the main use-cases for the wadler_lindig
library: to define useful, well-formatted reprs for complicated types.
Now let's chase through how this example was constructed. At the top level, we called wadler_lindig.pprint
(or wadler_lindig.pformat
). This called the __pdoc__
method of the top-level object (a FunctionCall
), and formatted the result. Inside that __pdoc__
method, we used wadler_lindig.pdoc
to get the pretty-documents of its components, which we then compose together.
Finally as you can see, we've also taken the opportunity to show off our ability to use ANSI colours!
Next example: take a look at the methods example for how to elegantly construct nested structures of documents.