-
Notifications
You must be signed in to change notification settings - Fork 5
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #59 from datarootsio/add-rich-tables
Add rich tables
- Loading branch information
Showing
8 changed files
with
242 additions
and
59 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,64 @@ | ||
"""Rich helpers functions for rich renderables in data models.""" | ||
from html.parser import HTMLParser | ||
from typing import Any, List, Optional, Tuple | ||
|
||
from rich import box | ||
from rich.table import Table | ||
|
||
HtmlAttr = Tuple[str, Optional[str]] | ||
|
||
|
||
class HtmlTable(HTMLParser): | ||
"""Rich table from HTML string.""" | ||
|
||
def __init__(self, html: str, *args: Any, **kwargs: Any) -> None: | ||
"""Initialize parser.""" | ||
super().__init__(*args, **kwargs) | ||
self.table = self.thead = self.tbody = self.body = self.th = self.td = False | ||
self.headers: List[str] = [] | ||
self.row: List[str] = [] | ||
self.rows: List[List[str]] = [] | ||
self.feed(html) | ||
|
||
def handle_starttag(self, tag: str, attrs: List[HtmlAttr]) -> None: | ||
"""Active tags are indicated via instance boolean properties.""" | ||
if getattr(self, tag, None): | ||
raise ValueError(f"Already in `{tag}`.") | ||
setattr(self, tag, True) | ||
|
||
def handle_endtag(self, tag: str) -> None: | ||
"""Write table properties when closing tags.""" | ||
if not getattr(self, tag): | ||
raise ValueError(f"Cannot end unopened `{tag}`.") | ||
|
||
# If we are ending a row, either set a table header or row | ||
if tag == "tr": | ||
if self.thead: | ||
self.headers = self.row | ||
if self.tbody: | ||
self.rows.append(self.row) | ||
self.row = [] # restart row values | ||
setattr(self, tag, False) | ||
|
||
def handle_data(self, data: str) -> None: | ||
"""Append data depending on active tags.""" | ||
if self.table and (self.th or self.td): | ||
self.row.append(data) | ||
|
||
def rich(self, **tbl_kwargs: Any) -> Optional[Table]: | ||
"""Generate `rich` representation of table.""" | ||
if not self.rows and not self.headers: # HTML is not a table | ||
return None | ||
|
||
_ncols = len(self.rows[0]) | ||
_headers = [""] * (_ncols - len(self.headers)) + self.headers | ||
if any(len(row) != _ncols for row in self.rows): | ||
raise ValueError(f"Expected all rows to have {_ncols} columns.") | ||
|
||
_box = tbl_kwargs.pop("box", box.SIMPLE_HEAVY) | ||
_row_styles = tbl_kwargs.pop("row_styles", ["on bright_black", ""]) | ||
|
||
table = Table(*_headers, box=_box, row_styles=_row_styles, **tbl_kwargs) | ||
for row in self.rows: | ||
table.add_row(*row) | ||
return table |
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,114 @@ | ||
from databooks.data_models.rich_helpers import HtmlTable | ||
from tests.test_tui import render | ||
|
||
|
||
def test_html_table() -> None: | ||
"""HTML can be rendered to a `rich` table.""" | ||
html = [ | ||
"<div>\n", | ||
"<style scoped>\n", | ||
" .dataframe tbody tr th:only-of-type {\n", | ||
" vertical-align: middle;\n", | ||
" }\n", | ||
"\n", | ||
" .dataframe tbody tr th {\n", | ||
" vertical-align: top;\n", | ||
" }\n", | ||
"\n", | ||
" .dataframe thead th {\n", | ||
" text-align: right;\n", | ||
" }\n", | ||
"</style>\n", | ||
'<table border="1" class="dataframe">\n', | ||
" <thead>\n", | ||
' <tr style="text-align: right;">\n', | ||
" <th></th>\n", | ||
" <th>col0</th>\n", | ||
" <th>col1</th>\n", | ||
" <th>col2</th>\n", | ||
" </tr>\n", | ||
" </thead>\n", | ||
" <tbody>\n", | ||
" <tr>\n", | ||
" <th>0</th>\n", | ||
" <td>0.849474</td>\n", | ||
" <td>0.756456</td>\n", | ||
" <td>0.268569</td>\n", | ||
" </tr>\n", | ||
" <tr>\n", | ||
" <th>1</th>\n", | ||
" <td>0.511937</td>\n", | ||
" <td>0.357224</td>\n", | ||
" <td>0.570879</td>\n", | ||
" </tr>\n", | ||
" <tr>\n", | ||
" <th>2</th>\n", | ||
" <td>0.836116</td>\n", | ||
" <td>0.928280</td>\n", | ||
" <td>0.946514</td>\n", | ||
" </tr>\n", | ||
" <tr>\n", | ||
" <th>3</th>\n", | ||
" <td>0.803129</td>\n", | ||
" <td>0.540215</td>\n", | ||
" <td>0.335783</td>\n", | ||
" </tr>\n", | ||
" <tr>\n", | ||
" <th>4</th>\n", | ||
" <td>0.074853</td>\n", | ||
" <td>0.661168</td>\n", | ||
" <td>0.344527</td>\n", | ||
" </tr>\n", | ||
" <tr>\n", | ||
" <th>5</th>\n", | ||
" <td>0.299696</td>\n", | ||
" <td>0.782420</td>\n", | ||
" <td>0.970147</td>\n", | ||
" </tr>\n", | ||
" <tr>\n", | ||
" <th>6</th>\n", | ||
" <td>0.159906</td>\n", | ||
" <td>0.566822</td>\n", | ||
" <td>0.243798</td>\n", | ||
" </tr>\n", | ||
" <tr>\n", | ||
" <th>7</th>\n", | ||
" <td>0.896461</td>\n", | ||
" <td>0.174406</td>\n", | ||
" <td>0.758376</td>\n", | ||
" </tr>\n", | ||
" <tr>\n", | ||
" <th>8</th>\n", | ||
" <td>0.708324</td>\n", | ||
" <td>0.895195</td>\n", | ||
" <td>0.769364</td>\n", | ||
" </tr>\n", | ||
" <tr>\n", | ||
" <th>9</th>\n", | ||
" <td>0.860726</td>\n", | ||
" <td>0.381919</td>\n", | ||
" <td>0.329727</td>\n", | ||
" </tr>\n", | ||
" </tbody>\n", | ||
"</table>\n", | ||
"</div>", | ||
] | ||
assert ( | ||
render(HtmlTable("".join(html)).rich()) | ||
== """\ | ||
\n\ | ||
col0 col1 col2 \n\ | ||
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ \n\ | ||
0 0.849474 0.756456 0.268569 \n\ | ||
1 0.511937 0.357224 0.570879 \n\ | ||
2 0.836116 0.928280 0.946514 \n\ | ||
3 0.803129 0.540215 0.335783 \n\ | ||
4 0.074853 0.661168 0.344527 \n\ | ||
5 0.299696 0.782420 0.970147 \n\ | ||
6 0.159906 0.566822 0.243798 \n\ | ||
7 0.896461 0.174406 0.758376 \n\ | ||
8 0.708324 0.895195 0.769364 \n\ | ||
9 0.860726 0.381919 0.329727 \n\ | ||
\n\ | ||
""" | ||
) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters