This commit is contained in:
Will McGugan 2020-06-01 16:08:06 +01:00
parent bbfe0e0c1d
commit ad8523ebaf
13 changed files with 105 additions and 27 deletions

View File

@ -10,6 +10,16 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
### Changed
- Changed defaults of Table.grid
- Polished listdir.py example
### Added
- Added width argument to Columns
### Fixed
- Fixed for `columns_first` argument in Columns
- Fixed incorrect padding in columns with fixed width
## [1.3.0] - 2020-05-31

View File

@ -1,3 +1,9 @@
"""
This example shows how to display content in columns.
The data is pulled from https://randomuser.me
"""
import json
from urllib.request import urlopen

View File

@ -1,7 +1,5 @@
"""
A rudimentary URL downloader (like wget or curl) to demonstrate Rich progress bars.
"""
from concurrent.futures import ThreadPoolExecutor

View File

@ -1,3 +1,7 @@
"""
This example demonstrates a simple text highlighter.
"""
from rich.console import Console
from rich.highlighter import RegexHighlighter
from rich.theme import Theme

View File

@ -1,3 +1,7 @@
"""
This example demonstrates the justify argument to print.
"""
from rich.console import Console
console = Console(width=20)

View File

@ -1,12 +1,35 @@
"""
A very simple `ls` clone.
If your terminal supports hyperlinks you should be able to launch files by clicking the filename
(usually with cmd / ctrl).
"""
import os
import sys
from rich import print
from rich.columns import Columns
from rich.text import Text
if len(sys.argv) < 2:
print("Usage: python columns.py DIRECTORY")
try:
root_path = sys.argv[1]
except IndexError:
print("Usage: python listdir.py DIRECTORY")
else:
directory = os.listdir(sys.argv[1])
columns = Columns(directory, equal=True, expand=True)
def make_filename_text(filename):
path = os.path.abspath(os.path.join(root_path, filename))
text = Text(filename, style="bold blue" if os.path.isdir(path) else "default")
text.stylize_all(f"link file://{path}")
text.highlight_regex(r"\..*?$", "bold")
return text
filenames = [
filename for filename in os.listdir(sys.argv[1]) if not filename.startswith(".")
]
filenames.sort(key=lambda filename: filename.lower())
filename_text = [make_filename_text(filename) for filename in filenames]
columns = Columns(filename_text, equal=True, column_first=True, padding=(0, 1))
print(columns)

View File

@ -1,7 +1,5 @@
"""
A simulation of Rich console logging.
"""
import time

View File

@ -1,3 +1,9 @@
"""
This example demonstrates how to write a custom highlighter.
"""
from random import randint
from rich import print

View File

@ -1,7 +1,5 @@
"""
Render a rich table.
Demonstrates how to render a table.
"""
from rich.console import Console

View File

@ -1,4 +1,5 @@
from collections import defaultdict
from itertools import chain
from operator import itemgetter
from typing import Dict, Iterable, List, Optional, Tuple
@ -15,6 +16,7 @@ class Columns(JupyterMixin):
Args:
renderables (Iterable[RenderableType]): Any number of Rich renderables (including str),
width (int, optional): The desired width of the columns, or None to auto detect. Defaults to None.
padding (PaddingDimensions, optional): Optional padding around cells. Defaults to (0, 1).
expand (bool, optional): Expand columns to full width. Defaults to False.
equal (bool, optional): Arrange in to equal sized columns. Defaults to False.
@ -26,12 +28,14 @@ class Columns(JupyterMixin):
self,
renderables: Iterable[RenderableType],
padding: PaddingDimensions = (0, 1),
width: int = None,
expand: bool = False,
equal: bool = False,
column_first: bool = False,
right_to_left: bool = False,
) -> None:
self.renderables = list(renderables)
self.width = width
self.padding = padding
self.expand = expand
self.equal = equal
@ -46,7 +50,8 @@ class Columns(JupyterMixin):
render_str(renderable) if isinstance(renderable, str) else renderable
for renderable in self.renderables
]
if not renderables:
return
_top, right, _bottom, left = Padding.unpack(self.padding)
width_padding = max(left, right)
max_width = options.max_width
@ -58,6 +63,8 @@ class Columns(JupyterMixin):
get_measurement(console, renderable, max_width).maximum
for renderable in renderables
]
if self.equal:
renderable_widths = [max(renderable_widths)] * len(renderable_widths)
def iter_renderables(
column_count: int,
@ -65,19 +72,26 @@ class Columns(JupyterMixin):
item_count = len(renderables)
if self.column_first:
width_renderables = list(zip(renderable_widths, renderables))
column_lengths: List[int] = [item_count // column_count] * column_count
for col_no in range(item_count % column_count):
column_lengths[col_no] += 1
row = 0
col = 0
for _ in width_renderables:
yield width_renderables[row * column_count + col]
row_count = (item_count + column_count - 1) // column_count
cells = [[-1] * column_count for _ in range(row_count)]
row = col = 0
for index in range(item_count):
cells[row][col] = index
column_lengths[col] -= 1
if column_lengths[col]:
row += 1
else:
col += 1
row = 0
for index in chain.from_iterable(cells):
if index == -1:
break
yield width_renderables[index]
else:
yield from zip(renderable_widths, renderables)
# Pad odd elements with spaces
@ -88,12 +102,16 @@ class Columns(JupyterMixin):
table = Table.grid(padding=self.padding, collapse_padding=True, pad_edge=False)
table.expand = self.expand
if self.equal:
maximum_column = max(renderable_widths)
column_count = max_width // maximum_column
if self.width is not None:
column_count = max_width // self.width
for _ in range(column_count):
table.add_column(ratio=1)
table.add_column(width=self.width)
else:
if self.equal:
table.expand = True
# for _ in range(column_count):
# table.add_column(ratio=1)
while column_count > 1:
widths.clear()
column_no = 0
@ -102,6 +120,7 @@ class Columns(JupyterMixin):
total_width = sum(widths.values()) + width_padding * (
len(widths) - 1
)
table.width = total_width
if total_width > max_width:
column_count = len(widths) - 1
break
@ -109,6 +128,7 @@ class Columns(JupyterMixin):
column_no = (column_no + 1) % column_count
else:
break
column_count = max(column_count, 1)
add_row = table.add_row
@ -143,4 +163,3 @@ if __name__ == "__main__": # pragma: no cover
columns.right_to_left = True
console.rule()
console.print(columns)
print(len(files))

View File

@ -194,10 +194,6 @@ class ConsoleDimensions(NamedTuple):
def _is_jupyter() -> bool:
"""Check if we're running in a Jupyter notebook."""
try:
from IPython.display import display
except ImportError:
return False
try:
get_ipython # type: ignore
except NameError:

View File

@ -374,8 +374,10 @@ class Table(JupyterMixin):
widths = [_range.minimum or 1 for _range in width_ranges]
else:
widths = [_range.maximum or 1 for _range in width_ranges]
padding_width = self.padding[1] + self.padding[3]
if self.expand:
ratios = [col.ratio or 0 for col in columns if col.flexible]
if any(ratios):
fixed_widths = [
@ -465,11 +467,21 @@ class Table(JupyterMixin):
for first, last, (style, renderable) in loop_first_last(raw_cells):
yield _Cell(style, add_padding(renderable, first, last))
def _get_padding_width(self, column_index) -> int:
"""Get extra width from padding."""
_, pad_right, _, pad_left = self.padding
if self.collapse_padding:
if column_index != 0:
pad_left = max(0, pad_right - pad_left)
return pad_left + pad_right
def _measure_column(
self, console: "Console", column_index: int, column: Column, max_width: int
) -> Measurement:
"""Get the minimum and maximum width of the column."""
padding_width = self.padding[1] + self.padding[3]
padding_width = self._get_padding_width(column_index)
if column.width is not None:
# Fixed width column
return Measurement(

View File

@ -42,12 +42,16 @@ def render():
columns.expand = True
console.print(columns)
console.print()
columns.width = 16
console.print(columns)
console.print()
render_result = console.file.getvalue()
return render_result
def test_render():
expected = "Ursus americanus American buffalo Bison bison American crow \nCorvus brachyrhynchos American marten Martes americana American racer \nColuber constrictor American woodcock Scolopax minor Anaconda (unidentified)\nEunectes sp. Andean goose Chloephaga melanoptera Ant \nAnteater, australian spiny Tachyglossus aculeatus Anteater, giant Myrmecophaga tridactyla\n\nUrsus americanus Corvus brachyrhynchos Coluber constrictor Eunectes sp. \nAnteater, australian spiny American buffalo American marten American woodcock \nAndean goose Tachyglossus aculeatus Bison bison Martes americana \nScolopax minor Chloephaga melanoptera Anteater, giant American crow \nAmerican racer Anaconda (unidentified) Ant Myrmecophaga tridactyla\n\nEunectes sp. Coluber constrictor Corvus brachyrhynchos Ursus americanus \nAmerican woodcock American marten American buffalo Anteater, australian spiny\nMartes americana Bison bison Tachyglossus aculeatus Andean goose \nAmerican crow Anteater, giant Chloephaga melanoptera Scolopax minor \nMyrmecophaga tridactyla Ant Anaconda (unidentified) American racer \n\nMartes americana American crow Ursus americanus \nAnt Eunectes sp. American woodcock \nCorvus brachyrhynchos American buffalo Anteater, giant \nAndean goose Scolopax minor American racer \nBison bison Myrmecophaga tridactyla Anteater, australian spiny \nAnaconda (unidentified) Coluber constrictor American marten \n Tachyglossus aculeatus Chloephaga melanoptera \n\n"
expected = "Ursus americanus American buffalo Bison bison American crow \nCorvus brachyrhynchos American marten Martes americana American racer \nColuber constrictor American woodcock Scolopax minor Anaconda (unidentified)\nEunectes sp. Andean goose Chloephaga melanoptera Ant \nAnteater, australian spiny Tachyglossus aculeatus Anteater, giant Myrmecophaga tridactyla\n\nUrsus americanus American marten Scolopax minor Ant \nAmerican buffalo Martes americana Anaconda (unidentified) Anteater, australian spiny\nBison bison American racer Eunectes sp. Tachyglossus aculeatus \nAmerican crow Coluber constrictor Andean goose Anteater, giant \nCorvus brachyrhynchos American woodcock Chloephaga melanoptera Myrmecophaga tridactyla \n\nAnt Scolopax minor American marten Ursus americanus \nAnteater, australian spiny Anaconda (unidentified) Martes americana American buffalo \nTachyglossus aculeatus Eunectes sp. American racer Bison bison \nAnteater, giant Andean goose Coluber constrictor American crow \nMyrmecophaga tridactyla Chloephaga melanoptera American woodcock Corvus brachyrhynchos\n\nChloephaga melanoptera American racer Ursus americanus \nAnt Coluber constrictor American buffalo \nAnteater, australian spiny American woodcock Bison bison \nTachyglossus aculeatus Scolopax minor American crow \nAnteater, giant Anaconda (unidentified) Corvus brachyrhynchos \nMyrmecophaga tridactyla Eunectes sp. American marten \n Andean goose Martes americana \n\nTachyglossus Chloephaga Anaconda Coluber Corvus Ursus americanus\naculeatus melanoptera (unidentified) constrictor brachyrhynchos \nAnteater, giant Ant Eunectes sp. American American marten American buffalo\n woodcock \nMyrmecophaga Anteater, Andean goose Scolopax minor Martes americana Bison bison \ntridactyla australian spiny \n American racer American crow \n\n"
assert render() == expected