rich/docs/source/protocol.rst

72 lines
3.6 KiB
ReStructuredText
Raw Normal View History

2020-01-11 16:13:39 +00:00
.. _protocol:
2020-01-08 11:51:49 +00:00
Console Protocol
================
Rich supports a simple protocol to add rich formatting capabilities to custom objects, so you can :meth:`~rich.console.Console.print` your object with color, styles and formatting.
2020-01-12 11:43:23 +00:00
Use this for presentation or to display additional debugging information that might be hard to parse from a typical ``__repr__`` string.
2020-01-08 11:51:49 +00:00
2020-02-23 18:27:38 +00:00
Console Customization
---------------------
2020-01-08 11:51:49 +00:00
2020-02-23 18:27:38 +00:00
The easiest way to customize console output for your object is to implement a ``__rich__`` method. This method accepts no arguments, and should return an object that Rich knows how to render, such as a :class:`~rich.text.Text` or :class:`~rich.table.Table`. If you return a plain string it will be rendered as :ref:`console_markup`. Here's an example::
2020-01-08 11:51:49 +00:00
class MyObject:
2020-02-23 18:27:38 +00:00
def __rich__(self) -> str:
return "[bold cyan]MyObject()"
2020-01-08 11:51:49 +00:00
2020-02-23 18:27:38 +00:00
If you were to print or log an instance of ``MyObject`` it would render as ``MyObject()`` in bold cyan. Naturally, you would want to put this to better use, perhaps by adding specialized syntax highlighting.
2020-01-08 11:51:49 +00:00
Console Render
--------------
2020-02-23 18:27:38 +00:00
The ``__rich__`` method is limited to a single renderable object. For more advanced rendering, add a ``__console__`` method to your class.
2020-01-08 11:51:49 +00:00
2020-02-23 18:27:38 +00:00
The ``__console__`` method should accept a :class:`~rich.console.Console` and a :class:`~rich.console.ConsoleOptions` instance. It should return an iterable of other renderable objects. Although that means it *could* return a container such as a list, it generally easier implemented by using the ``yield`` statement (making the method a generator).
2020-01-08 11:51:49 +00:00
Here's an example of a ``__console__`` method::
2020-02-23 18:27:38 +00:00
from rich.console import Console, ConsoleOptions, RenderResult
2020-01-11 16:13:39 +00:00
@dataclass
class Student:
2020-02-23 18:27:38 +00:00
id: int
2020-01-11 16:13:39 +00:00
name: str
age: int
2020-02-23 18:27:38 +00:00
def __console__(self, console: Console, options: ConsoleOptions) -> RenderResult:
yield f"[b]Student:[/b] #{self.id}"
2020-01-11 16:13:39 +00:00
my_table = Table("Attribute, "Value")
my_table.add_row("name", self.name)
my_table.add_row("age", str(self.age))
2020-01-08 11:51:49 +00:00
yield my_table
2020-01-11 16:13:39 +00:00
If you were to print a ``Student`` instance, it would render a simple table to the terminal.
Low Level Render
~~~~~~~~~~~~~~~~
For complete control over how a custom object is rendered to the terminal, you can yield :class:`~rich.segment.Segment` objects. A Segment consists of a piece of text and an optional Style. The following example, writes multi-colored text when rendering a ``MyObject`` instance::
class MyObject:
2020-02-23 18:27:38 +00:00
def __console__(self, console: Console, options: ConsoleOptions) -> RenderResult:
2020-01-11 16:13:39 +00:00
yield Segment("My", "magenta")
yield Segment("Object", green")
yield Segment("()", "cyan")
Console Width
~~~~~~~~~~~~~
2020-02-23 18:27:38 +00:00
Sometimes Rich needs to know how many characters an object will take up when rendering. The :class:`~rich.table.Table` class, for instance, will use this information to calculate the optimal dimensions for the columns. If you aren't using one of the standard classes, you will need to supply a ``__console_width__`` method which accepts the maximum width as an integer and returns a :class:`~rich.render_width.RenderWidth` object. The RenderWidth object should contain the *minimum* and *maximum* number of characters required to render.
2020-01-11 16:13:39 +00:00
2020-02-23 18:27:38 +00:00
For example, if we are rendering a chess board, it would require a minimum of 8 characters to render. The maximum can be left as the maximum available width (assuming a centered board)::
2020-01-11 16:13:39 +00:00
class ChessBoard:
def __console_width__(self, max_width: int) -> RenderWidth:
return RenderWidth(8, max_width)