|
| 1 | +from typing import List, Tuple |
| 2 | + |
| 3 | + |
| 4 | +def split_first_last(l: list, k: int) -> Tuple[list, list]: |
| 5 | + _len = len(l) |
| 6 | + if _len <= 1: |
| 7 | + return l, [] |
| 8 | + is_odd = k % 2 |
| 9 | + k = min(k // 2, _len // 2) |
| 10 | + return l[:(k+int(is_odd))], l[-k:] |
| 11 | + |
| 12 | + |
| 13 | +def to_plural(unit_str: str, k: int) -> str: |
| 14 | + return unit_str + ('' if k < 2 else 's') |
| 15 | + |
| 16 | + |
| 17 | +def collapsed_row(l: list, is_skip: bool) -> list: |
| 18 | + _first, _last = split_first_last(l, len(l)) |
| 19 | + return _first + (['...'] if is_skip else []) + _last |
| 20 | + |
| 21 | + |
| 22 | +def collapse_str(s: str, width: int) -> str: |
| 23 | + if len(s) <= width: |
| 24 | + return s |
| 25 | + return s[:min(len(s), width - 3)] + '...' |
| 26 | + |
| 27 | + |
| 28 | +def row_str(l: list, delimiter: str = '') -> str: |
| 29 | + return f" {delimiter} ".join(l) + "\n" |
| 30 | + |
| 31 | + |
| 32 | +def row_padded(row: list, widths: list) -> List[str]: |
| 33 | + return [row[i].ljust(widths[i]) for i in range(len(row))] |
| 34 | + |
| 35 | + |
| 36 | +def stringify(all_items: List[dict]) -> str: |
| 37 | + """Return 3 each rows from the top and the bottom. |
| 38 | +
|
| 39 | + Returns: |
| 40 | + str: The first and last 3 rows of the caller object. |
| 41 | +
|
| 42 | + Example: |
| 43 | + >>> db |
| 44 | + age grouped ... job name |
| 45 | + 32 True ... Camera operator Layne |
| 46 | + 17 False ... Flying instructor Somerled |
| 47 | + 9 True ... Inventor Joon-Ho |
| 48 | + ... ... ... ... ... |
| 49 | + 23 None ... Publican Melanie |
| 50 | + 54 True ... Racing driver Eike |
| 51 | + 41 None ... Barrister Tanja |
| 52 | +
|
| 53 | +
|
| 54 | + [100 items, 9 keys] |
| 55 | + """ |
| 56 | + # Collect key names to be column |
| 57 | + keys = set() |
| 58 | + for item in all_items: |
| 59 | + keys |= set(item.keys()) |
| 60 | + total_rows = len(all_items) |
| 61 | + total_cols = len(keys) |
| 62 | + |
| 63 | + # Display options |
| 64 | + keys = sorted(list(keys)) |
| 65 | + rows_display = 6 |
| 66 | + cols_display = 4 |
| 67 | + text_max_width = 12 |
| 68 | + |
| 69 | + # Collect rows by columns and collapse them |
| 70 | + first_cols, last_cols = split_first_last(keys, cols_display) |
| 71 | + first_rows, last_rows = split_first_last(all_items, rows_display) |
| 72 | + rows = first_rows + last_rows |
| 73 | + cols = first_cols + last_cols |
| 74 | + col_widths = [max(3, len(str(col))) for col in cols] |
| 75 | + table = [] |
| 76 | + for irow, row in enumerate(rows): |
| 77 | + t_row = [] |
| 78 | + for icol, col in enumerate(cols): |
| 79 | + try: |
| 80 | + stringified = str(row[col]) |
| 81 | + except KeyError: |
| 82 | + stringified = str(None) |
| 83 | + text = collapse_str(stringified, width=text_max_width) |
| 84 | + col_widths[icol] = max(col_widths[icol], len(text)) |
| 85 | + t_row.append(text) |
| 86 | + table.append(t_row) |
| 87 | + |
| 88 | + # Shortcut functions |
| 89 | + def _clp_row(l): return collapsed_row(l, is_skip=total_cols > cols_display) |
| 90 | + def _make_row_str(l): return row_str(_clp_row(l), delimiter='') |
| 91 | + def _padded(l): return row_padded(l, widths=col_widths) |
| 92 | + |
| 93 | + # Create result strings |
| 94 | + result = _make_row_str(_padded(first_cols + last_cols)) |
| 95 | + for irow, row in enumerate(table): |
| 96 | + s = _padded(row) |
| 97 | + result += _make_row_str(s) |
| 98 | + if total_rows > rows_display and irow + 1 == len(first_rows): |
| 99 | + result += _make_row_str(_padded(['...'] * (len(cols)))) |
| 100 | + |
| 101 | + result += "\n\n" + ", ".join([ |
| 102 | + f"[{total_rows} {to_plural('item', total_rows)}", |
| 103 | + f"{total_cols} {to_plural('key', total_cols)}]", |
| 104 | + ]) |
| 105 | + |
| 106 | + return result |
0 commit comments