Pretty Printing

In addition to syntax highlighting, Rich will format (i.e. pretty print) containers such as lists, dicts, and sets.

Run the following command to see an example of pretty printed output:

python -m rich.pretty

Note how the output will change to fit within the terminal width.

pprint method

The pprint() method offers a few more arguments you can use to tweak how objects are pretty printed. Here’s how you would import it:

>>> from rich.pretty import pprint
>>> pprint(locals())

Indent guides

Rich can draw indent guides to highlight the indent level of a data structure. These can make it easier to read more deeply nested output. The pprint method enables indent guides by default. You can set indent_guides=False to disable this feature.

Expand all

Rich is quite conservative about expanding data structures and will try to fit as much in each line as it can. If you prefer, you can tell Rich to fully expand all data structures by setting expand_all=True. Here’s an example:

>>> pprint(["eggs", "ham"], expand_all=True)

Truncating pretty output

Very long data structures can be difficult to read and you may find yourself scrolling through multiple pages in the terminal to find the data you are interested in. Rich can truncate containers and long strings to give you an overview without swamping your terminal.

If you set the max_length argument to an integer, Rich will truncate containers with more than the given number of elements. If data is truncated, Rich will display an ellipsis ... and the number of elements not shown.

Here’s an example:

>>> pprint(locals(), max_length=2)

If you set the max_string argument to an integer, Rich will truncate strings over that length. Truncated string will be appended with the number of characters that have not been shown. Here’s an example:

>>> pprint("Where there is a Will, there is a Way", max_string=21)

Pretty renderable

Rich offers a Pretty class which you can use to insert pretty printed data in to another renderable.

The following example displays pretty printed data within a simple panel:

from rich import print
from rich.pretty import Pretty
from rich.panel import Panel

pretty = Pretty(locals())
panel = Panel(pretty)
print(panel)

There are a large number of options to tweak the pretty formatting, See the Pretty reference for details.

Rich Repr Protocol

Rich is able to syntax highlight any output, but the formatting is restricted to built-in containers, dataclasses, and other objects Rich knows about, such as objects generated by the attrs library. To add Rich formatting capabilities to custom objects, you can implement the rich repr protocol.

Run the following command to see an example of what the Rich repr protocol can generate:

python -m rich.repr

First, let’s look at a class that might benefit from a Rich repr:

class Bird:
    def __init__(self, name, eats=None, fly=True, extinct=False):
        self.name = name
        self.eats = list(eats) if eats else []
        self.fly = fly
        self.extinct = extinct

    def __repr__(self):
        return f"Bird({self.name!r}, eats={self.eats!r}, fly={self.fly!r}, extinct={self.extinct!r})"

BIRDS = {
    "gull": Bird("gull", eats=["fish", "chips", "ice cream", "sausage rolls"]),
    "penguin": Bird("penguin", eats=["fish"], fly=False),
    "dodo": Bird("dodo", eats=["fruit"], fly=False, extinct=True)
}
print(BIRDS)

The result of this script would be:

{'gull': Bird('gull', eats=['fish', 'chips', 'ice cream', 'sausage rolls'], fly=True, extinct=False), 'penguin': Bird('penguin', eats=['fish'], fly=False, extinct=False), 'dodo': Bird('dodo', eats=['fruit'], fly=False, extinct=True)}

The output is long enough to wrap on to the next line, which can make it hard to read. The repr strings are informative but a little verbose since they include default arguments. If we print this with Rich, things are improved somewhat:

{
    'gull': Bird('gull', eats=['fish', 'chips', 'ice cream', 'sausage rolls'],
fly=True, extinct=False),
    'penguin': Bird('penguin', eats=['fish'], fly=False, extinct=False),
    'dodo': Bird('dodo', eats=['fruit'], fly=False, extinct=True)
}

Rich knows how to format the container dict, but the repr strings are still verbose, and there is some wrapping of the output (assumes an 80 character terminal).

We can solve both these issues by adding the following __rich_repr__ method:

def __rich_repr__(self):
    yield self.name
    yield "eats", self.eats
    yield "fly", self.fly, True
    yield "extinct", self.extinct, False

Now if we print the same object with Rich we would see the following:

{
    'gull': Bird(
        'gull',
        eats=['fish', 'chips', 'ice cream', 'sausage rolls']
    ),
    'penguin': Bird('penguin', eats=['fish'], fly=False),
    'dodo': Bird('dodo', eats=['fruit'], fly=False, extinct=True)
}

The default arguments have been omitted, and the output has been formatted nicely. The output remains readable even if we have less room in the terminal, or our objects are part of a deeply nested data structure:

{
    'gull': Bird(
        'gull',
        eats=[
            'fish',
            'chips',
            'ice cream',
            'sausage rolls'
        ]
    ),
    'penguin': Bird(
        'penguin',
        eats=['fish'],
        fly=False
    ),
    'dodo': Bird(
        'dodo',
        eats=['fruit'],
        fly=False,
        extinct=True
    )
}

You can add a __rich_repr__ method to any class to enable the Rich formatting. This method should return an iterable of tuples. You could return a list of tuples, but it’s easier to express with the yield keywords, making it a generator.

Each tuple specifies an element in the output.

  • yield value will generate a positional argument.

  • yield name, value will generate a keyword argument.

  • yield name, value, default will generate a keyword argument if value is not equal to default.

If you use None as the name, then it will be treated as a positional argument as well, in order to support having tuple positional arguments.

You can also tell Rich to generate the angular bracket style of repr, which tend to be used where there is no easy way to recreate the object’s constructor. To do this set the function attribute "angular" to True immediately after your __rich_repr__ method. For example:

__rich_repr__.angular = True

This will change the output of the Rich repr example to the following:

{
    'gull': <Bird 'gull' eats=['fish', 'chips', 'ice cream', 'sausage rolls']>,
    'penguin': <Bird 'penguin' eats=['fish'] fly=False>,
    'dodo': <Bird 'dodo' eats=['fruit'] fly=False extinct=True>
}

Note that you can add __rich_repr__ methods to third-party libraries without including Rich as a dependency. If Rich is not installed, then nothing will break. Hopefully more third-party libraries will adopt Rich repr methods in the future.

Typing

If you want to type the Rich repr method you can import and return rich.repr.Result, which will help catch logical errors:

import rich.repr


class Bird:
    def __init__(self, name, eats=None, fly=True, extinct=False):
        self.name = name
        self.eats = list(eats) if eats else []
        self.fly = fly
        self.extinct = extinct

    def __rich_repr__(self) -> rich.repr.Result:
        yield self.name
        yield "eats", self.eats
        yield "fly", self.fly, True
        yield "extinct", self.extinct, False

Automatic Rich Repr

Rich can generate a rich repr automatically if the parameters are named the same as your attributes.

To automatically build a rich repr, use the auto() class decorator. The Bird example above follows the above rule, so we don’t strictly need to implement our own __rich_repr__. The following code would generate the same repr:

import rich.repr

@rich.repr.auto
class Bird:
    def __init__(self, name, eats=None, fly=True, extinct=False):
        self.name = name
        self.eats = list(eats) if eats else []
        self.fly = fly
        self.extinct = extinct


BIRDS = {
    "gull": Bird("gull", eats=["fish", "chips", "ice cream", "sausage rolls"]),
    "penguin": Bird("penguin", eats=["fish"], fly=False),
    "dodo": Bird("dodo", eats=["fruit"], fly=False, extinct=True)
}
from rich import print
print(BIRDS)

Note that the decorator will also create a __repr__, so you will get an auto-generated repr even if you don’t print with Rich.

If you want to auto-generate the angular type of repr, then set angular=True on the decorator:

@rich.repr.auto(angular=True)
class Bird:
    def __init__(self, name, eats=None, fly=True, extinct=False):
        self.name = name
        self.eats = list(eats) if eats else []
        self.fly = fly
        self.extinct = extinct

Example

See repr.py for the example code used in this page.