Skip to content

Commit

Permalink
Merge pull request #2141 from Textualize/progress-docs
Browse files Browse the repository at this point in the history
Progress docs
  • Loading branch information
willmcgugan committed Apr 3, 2022
2 parents 6b9adfa + d852cd1 commit 489fafc
Show file tree
Hide file tree
Showing 6 changed files with 68 additions and 48 deletions.
5 changes: 1 addition & 4 deletions CHANGELOG.md
Expand Up @@ -5,14 +5,11 @@ All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).

## 12.1.0
## [12.1.0] - 2022-04-03

### Added

- Progress.open and Progress.wrap_file method to track the progress while reading from a file or file-like object https://github.com/willmcgugan/rich/pull/1759

### Added

- SVG export functionality https://github.com/Textualize/rich/pull/2101

### Fixed
Expand Down
39 changes: 20 additions & 19 deletions docs/source/progress.rst
Expand Up @@ -212,37 +212,38 @@ If the :class:`~rich.progress.Progress` class doesn't offer exactly what you nee
Reading from a file
~~~~~~~~~~~~~~~~~~~

You can obtain a progress-tracking reader using the :meth:`~rich.progress.Progress.open` method by giving it a path. You can specify the number of bytes to be read, but by default :meth:`~rich.progress.Progress.open` will query the size of the file with :func:`os.stat`. You are responsible for closing the file, and you should consider using a *context* to make sure it is closed ::
Rich provides an easy way to generate a progress bar for reading a file. If you call :func:`~rich.progress.open` it will return a context manager which displays a progress bar while you read. This is particularly useful when you can't easily modify the code that does the reading.

The following example shows how we might show progress for reading a JSON file::

import json
from rich.progress import Progress
import rich.progress

with Progress() as progress:
with progress.open("data.json", "rb") as file:
json.load(file)
with rich.progress.open("data.json", "rb") as file:
data = json.load(file)
print(data)

If you already have a file object, you can call :func:`~rich.progress.wrap_file` which returns a context manager that wraps your file so that it displays a progress bar. If you use this function you will need to set the number of bytes or characters you expect to read.

Note that in the above snippet we use the `"rb"` mode, because we needed the file to be opened in binary mode to pass it to :func:`json.load`. If the API consuming the file is expecting an object in *text mode* (for instance, :func:`csv.reader`), you can open the file with the `"r"` mode, which happens to be the default ::
Here's an example that reads a url from the internet::

from rich.progress import Progress
from time import sleep
from urllib.request import urlopen

with Progress() as progress:
with progress.open("README.md") as file:
for line in file:
print(line)
from rich.progress import wrap_file

response = urlopen("https://www.textualize.io")
size = int(response.headers["Content-Length"])

Reading from a file-like object
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
with wrap_file(response, size) as file:
for line in file:
print(line.decode("utf-8"), end="")
sleep(0.1)

You can obtain a progress-tracking reader wrapping a file-like object using the :meth:`~rich.progress.Progress.wrap_file` method. The file-like object must be in *binary mode*, and a total must be provided, unless it was provided to a :class:`~rich.progress.Task` created beforehand. The returned reader may be used in a context, but will not take care of closing the wrapped file ::

import json
from rich.progress import Progress
If you expect to be reading from multiple files, you can use :meth:`~rich.progress.Progress.open` or :meth:`~rich.progress.Progress.wrap_file` to add a file progress to an existing Progress instance.

with Progress() as progress:
with open("data.json", "rb") as file:
json.load(progress.wrap_file(file, total=2048))
See `cp_progress.py <https://github.com/willmcgugan/rich/blob/master/examples/cp_progress.py>` for a minimal clone of the ``cp`` command which shows a progress bar as the file is copied.


Multiple Progress
Expand Down
28 changes: 4 additions & 24 deletions examples/cp_progress.py
Expand Up @@ -5,35 +5,15 @@
import shutil
import sys

from rich.progress import (
BarColumn,
DownloadColumn,
Progress,
TaskID,
TextColumn,
TimeRemainingColumn,
TransferSpeedColumn,
)

progress = Progress(
TextColumn("[bold blue]{task.description}", justify="right"),
BarColumn(bar_width=None),
"[progress.percentage]{task.percentage:>3.1f}%",
"•",
DownloadColumn(),
"•",
TransferSpeedColumn(),
"•",
TimeRemainingColumn(),
)
from rich.progress import Progress

if __name__ == "__main__":
if len(sys.argv) == 3:

with progress:
with Progress() as progress:
desc = os.path.basename(sys.argv[1])
with progress.read(sys.argv[1], description=desc) as src:
with progress.open(sys.argv[1], "rb", description=desc) as src:
with open(sys.argv[2], "wb") as dst:
shutil.copyfileobj(src, dst)
else:
print("Copy a file with a progress bar.")
print("Usage:\n\tpython cp_progress.py SRC DST")
16 changes: 16 additions & 0 deletions examples/file_progress.py
@@ -0,0 +1,16 @@
from time import sleep
from urllib.request import urlopen

from rich.progress import wrap_file

# Read a URL with urlopen
response = urlopen("https://www.textualize.io")
# Get the size from the headers
size = int(response.headers["Content-Length"])

# Wrap the response so that it update progress

with wrap_file(response, size) as file:
for line in file:
print(line.decode("utf-8"), end="")
sleep(0.1)
26 changes: 26 additions & 0 deletions examples/save_table_svg.py
@@ -0,0 +1,26 @@
"""
Demonstrates how to export a SVG
"""

from rich.console import Console
from rich.table import Table

table = Table(title="Star Wars Movies")

table.add_column("Released", style="cyan", no_wrap=True)
table.add_column("Title", style="magenta")
table.add_column("Box Office", justify="right", style="green")

table.add_row("Dec 20, 2019", "Star Wars: The Rise of Skywalker", "$952,110,690")
table.add_row("May 25, 2018", "Solo: A Star Wars Story", "$393,151,347")
table.add_row("Dec 15, 2017", "Star Wars Ep. V111: The Last Jedi", "$1,332,539,889")
table.add_row("Dec 16, 2016", "Rogue One: A Star Wars Story", "$1,332,439,889")

console = Console(record=True)
console.print(table, justify="center")
console.save_svg("table.svg", title="save_table_svg.py")

import os
import webbrowser

webbrowser.open(f"file://{os.path.abspath('table.svg')}")
2 changes: 1 addition & 1 deletion rich/console.py
Expand Up @@ -2350,7 +2350,7 @@ def export_svg(
)
)

fragments = []
fragments: List[str] = []
theme_foreground_color = _theme.foreground_color.hex
theme_background_color = _theme.background_color.hex

Expand Down

0 comments on commit 489fafc

Please sign in to comment.