Skip to content

Commit

Permalink
Merge pull request #382 from nathanrpage97/feat/add-live-table-proposal
Browse files Browse the repository at this point in the history
Add live updating for any render
  • Loading branch information
willmcgugan committed Dec 3, 2020
2 parents 1ea55b4 + 4236348 commit b1612f9
Show file tree
Hide file tree
Showing 10 changed files with 853 additions and 87 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ mypy_report
docs/build
docs/source/_build
tools/*.txt
playground/

# Byte-compiled / optimized / DLL files
__pycache__/
Expand Down
1 change: 1 addition & 0 deletions CONTRIBUTORS.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,3 +7,4 @@ The following people have contributed to the development of Rich:
- [Oleksis Fraga](https://github.com/oleksis)
- [Hedy Li](https://github.com/hedythedev)
- [Will McGugan](https://github.com/willmcgugan)
- [Nathan Page](https://github.com/nathanrpage97)
11 changes: 6 additions & 5 deletions docs/source/index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -19,16 +19,17 @@ Welcome to Rich's documentation!
logging.rst
traceback.rst
prompt.rst

tables.rst
padding.rst
panel.rst
group.rst
panel.rst
group.rst
columns.rst
live.rst
progress.rst
markdown.rst
syntax.rst
syntax.rst

protocol.rst

reference.rst
Expand Down
172 changes: 172 additions & 0 deletions docs/source/live.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,172 @@
.. _live:

Live Display
============

Rich can display continiuously updated information for any renderable.

To see some live display examples, try this from the command line::

python -m rich.live

.. note::

If you see ellipsis "...", this indicates that the terminal is not tall enough to show the full table.

Basic Usage
-----------

The basic usage can be split into two use cases.

1. Same Renderable
~~~~~~~~~~~~~~~~~~

When keeping the same renderable, you simply pass the :class:`~rich.console.RenderableType` you would like to see updating and provide
a ``refresh_per_second`` parameter. The Live :class:`~rich.live.Live` will automatically update the console at the provided refresh rate.


**Example**::

import time

from rich.live import Live
from rich.table import Table

table = Table()
table.add_column("Row ID")
table.add_column("Description")
table.add_column("Level")

with Live(table, refresh_per_second=4): # update 4 times a second to feel fluid
for row in range(12):
time.sleep(0.4) # arbitrary delay
# update the renderable internally
table.add_row(f"{row}", f"description {row}", "[red]ERROR")


2. New Renderable
~~~~~~~~~~~~~~~~~

You can also provide constant new renderable to :class:`~rich.live.Live` using the :meth:`~rich.live.Live.update` function. This allows you to
completely change what is rendered live.

**Example**::

import random
import time

from rich.live import Live
from rich.table import Table


def generate_table() -> Table:

table = Table()
table.add_column("ID")
table.add_column("Value")
table.add_column("Status")

for row in range(random.randint(2, 6)):
value = random.random() * 100
table.add_row(
f"{row}", f"{value:3.2f}", "[red]ERROR" if value < 50 else "[green]SUCCESS"
)
return table


with Live(refresh_per_second=4) as live:
for _ in range(40):
time.sleep(0.4)
live.update(generate_table())

Advanced Usage
--------------

Transient Display
~~~~~~~~~~~~~~~~~

Normally when you exit live context manager (or call :meth:`~rich.live.Live.stop`) the last refreshed item remains in the terminal with the cursor on the following line.
You can also make the live display disappear on exit by setting ``transient=True`` on the Live constructor. Here's an example::

with Live(transient=True) as live:
...

Auto refresh
~~~~~~~~~~~~

By default, the live display will refresh 4 times a second. You can set the refresh rate with the ``refresh_per_second`` argument on the :class:`~rich.live.Live` constructor.
You should set this to something lower than 4 if you know your updates will not be that frequent or higher for a smoother feeling.

You might want to disable auto-refresh entirely if your updates are not very frequent, which you can do by setting ``auto_refresh=False`` on the constructor.
If you disable auto-refresh you will need to call :meth:`~rich.live.Live.refresh` manually or :meth:`~rich.live.Live.update` with ``refresh=True``.

Vertical Overflow
~~~~~~~~~~~~~~~~~

By default, the live display will display ellipsis if the renderable is too large for the terminal. You can adjust this by setting the
``vertical_overflow`` argument on the :class:`~rich.live.Live` constructor.

- crop: Show renderable up to the terminal height. The rest is hidden.
- ellipsis: Similar to crop except last line of the terminal is replaced with "...". This is the default behavior.
- visible: Will allow the whole renderable to be shown. Note that the display cannot be properly cleared in this mode.

.. note::

Once the live display stops on a non-transient renderable, the last frame will render as **visible** since it doesn't have to be cleared.

Complex Renders
~~~~~~~~~~~~~~~

Refer to the :ref:`Render Groups` about combining multiple :class:`RenderableType` together so that it may be passed into the :class:`~rich.live.Live` constructor
or :meth:`~rich.live.Live.update` method.

For more powerful structuring it is also possible to use nested tables.


Print / log
~~~~~~~~~~~

The Live class will create an internal Console object which you can access via ``live.console``. If you print or log to this console, the output will be displayed *above* the live display. Here's an example::

import time

from rich.live import Live
from rich.table import Table

table = Table()
table.add_column("Row ID")
table.add_column("Description")
table.add_column("Level")

with Live(table, refresh_per_second=4): # update 4 times a second to feel fluid
for row in range(12):
live.console.print("Working on row #{row}")
time.sleep(0.4)
table.add_row(f"{row}", f"description {row}", "[red]ERROR")


If you have another Console object you want to use, pass it in to the :class:`~rich.live.Live` constructor. Here's an example::

from my_project import my_console

with Live(console=my_console) as live:
my_console.print("[bold blue]Starting work!")
...

.. note::

If you are passing in a file console, the live display only show the last item once the live context is left.

Redirecting stdout / stderr
~~~~~~~~~~~~~~~~~~~~~~~~~~~

To avoid breaking the live display visuals, Rich will redirect ``stdout`` and ``stderr`` so that you can use the builtin ``print`` statement.
This feature is enabled by default, but you can disable by setting ``redirect_stdout`` or ``redirect_stderr`` to ``False``.


Examples
--------

See `table_movie.py <https://github.com/willmcgugan/rich/blob/master/examples/table_movie.py>`_ and
`top_lite_simulator.py <https://github.com/willmcgugan/rich/blob/master/examples/top_lite_simulator.py>`_
for deeper examples of live displaying.
5 changes: 3 additions & 2 deletions docs/source/reference.rst
Original file line number Diff line number Diff line change
Expand Up @@ -3,15 +3,16 @@ Reference

.. toctree::
:maxdepth: 3

reference/align.rst
reference/bar.rst
reference/color.rst
reference/columns.rst
reference/console.rst
reference/emoji.rst
reference/highlighter.rst
reference/highlighter.rst
reference/init.rst
reference/live.rst
reference/logging.rst
reference/markdown.rst
reference/markup.rst
Expand Down
5 changes: 5 additions & 0 deletions docs/source/reference/live.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
rich.live
=========

.. automodule:: rich.live
:members:

0 comments on commit b1612f9

Please sign in to comment.