Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Progress docs #2141

Merged
merged 4 commits into from Apr 3, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
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 pyproject.toml
Expand Up @@ -2,7 +2,7 @@
name = "rich"
homepage = "https://github.com/willmcgugan/rich"
documentation = "https://rich.readthedocs.io/en/latest/"
version = "12.0.1"
version = "12.1.0"
description = "Render rich text, tables, progress bars, syntax highlighting, markdown and more to the terminal"
authors = ["Will McGugan <willmcgugan@gmail.com>"]
license = "MIT"
Expand Down
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