griddle
1import os 2from typing import Any, Iterable, Mapping, Sequence 3 4from tabulate import tabulate 5 6 7def griddy( 8 data: Mapping[str, Iterable[Any]] | Iterable[Iterable[Any]], 9 headers: str | dict[str, str] | Sequence[str] = (), 10 shrink_to_terminal: bool = True, 11 margin: int = 10, 12 table_format: str = "rounded_grid", 13 disable_numparse: bool = True, 14) -> str: 15 """Convert `data` into a formatted string grid representation. 16 17 #### :params: 18 19 * `headers`: Can either be an explicit list of column names, `"keys"`, or `"firstrow"`. 20 If not given, the grid will have no headers. 21 22 * `shrink_to_terminal`: When `True`, `griddy` will limit column widths so that the total width of the output will fit within the terminal. 23 24 * `margin`: When shrinking to the terminal, `griddy` will try to maximize the output width such that `terminal_width - margin < output_width < terminal_width`. 25 The larger this value, the larger the acceptable output width and, likely, the faster this function will return. 26 Note: `griddy` will, internally, increase the margin when necessary to avoid getting stuck in an infinite loop. 27 28 29 * `table_format`: The grid asthetic. See the `tabulate` package for a full list of options. 30 31 * `disable_numparse`: Turn off treating and aligning numbers differently from non-numbers. 32 33 """ 34 output = tabulate( 35 data, 36 headers=headers, 37 disable_numparse=disable_numparse, 38 tablefmt=table_format, 39 ) 40 if not shrink_to_terminal: 41 return output 42 43 grid = lambda w: tabulate( 44 data, 45 headers=headers, 46 disable_numparse=True, 47 tablefmt=table_format, 48 maxcolwidths=w, 49 ) 50 51 terminal_width = os.get_terminal_size().columns 52 max_col_width = terminal_width 53 current_width = output.find("\n") 54 if current_width < terminal_width: 55 return output 56 57 previous_col_width = max_col_width 58 acceptable_width = terminal_width - margin 59 while max_col_width > 1: 60 if current_width >= terminal_width: 61 previous_col_width = max_col_width 62 max_col_width = int(max_col_width * 0.5) 63 elif current_width < terminal_width: 64 # Without lowering acceptable width, this condition will cause an infinite loop 65 if max_col_width == previous_col_width - 1: 66 acceptable_width -= margin 67 max_col_width = int( 68 max_col_width + (0.5 * (previous_col_width - max_col_width)) 69 ) 70 # Check if output width is in the acceptable range 71 output = grid(max_col_width) 72 current_width = output.find("\n") 73 if acceptable_width < current_width < terminal_width: 74 return output 75 raise RuntimeError("Could not resize grid to fit within the terminal :/.")
8def griddy( 9 data: Mapping[str, Iterable[Any]] | Iterable[Iterable[Any]], 10 headers: str | dict[str, str] | Sequence[str] = (), 11 shrink_to_terminal: bool = True, 12 margin: int = 10, 13 table_format: str = "rounded_grid", 14 disable_numparse: bool = True, 15) -> str: 16 """Convert `data` into a formatted string grid representation. 17 18 #### :params: 19 20 * `headers`: Can either be an explicit list of column names, `"keys"`, or `"firstrow"`. 21 If not given, the grid will have no headers. 22 23 * `shrink_to_terminal`: When `True`, `griddy` will limit column widths so that the total width of the output will fit within the terminal. 24 25 * `margin`: When shrinking to the terminal, `griddy` will try to maximize the output width such that `terminal_width - margin < output_width < terminal_width`. 26 The larger this value, the larger the acceptable output width and, likely, the faster this function will return. 27 Note: `griddy` will, internally, increase the margin when necessary to avoid getting stuck in an infinite loop. 28 29 30 * `table_format`: The grid asthetic. See the `tabulate` package for a full list of options. 31 32 * `disable_numparse`: Turn off treating and aligning numbers differently from non-numbers. 33 34 """ 35 output = tabulate( 36 data, 37 headers=headers, 38 disable_numparse=disable_numparse, 39 tablefmt=table_format, 40 ) 41 if not shrink_to_terminal: 42 return output 43 44 grid = lambda w: tabulate( 45 data, 46 headers=headers, 47 disable_numparse=True, 48 tablefmt=table_format, 49 maxcolwidths=w, 50 ) 51 52 terminal_width = os.get_terminal_size().columns 53 max_col_width = terminal_width 54 current_width = output.find("\n") 55 if current_width < terminal_width: 56 return output 57 58 previous_col_width = max_col_width 59 acceptable_width = terminal_width - margin 60 while max_col_width > 1: 61 if current_width >= terminal_width: 62 previous_col_width = max_col_width 63 max_col_width = int(max_col_width * 0.5) 64 elif current_width < terminal_width: 65 # Without lowering acceptable width, this condition will cause an infinite loop 66 if max_col_width == previous_col_width - 1: 67 acceptable_width -= margin 68 max_col_width = int( 69 max_col_width + (0.5 * (previous_col_width - max_col_width)) 70 ) 71 # Check if output width is in the acceptable range 72 output = grid(max_col_width) 73 current_width = output.find("\n") 74 if acceptable_width < current_width < terminal_width: 75 return output 76 raise RuntimeError("Could not resize grid to fit within the terminal :/.")
Convert data
into a formatted string grid representation.
:params:
headers
: Can either be an explicit list of column names,"keys"
, or"firstrow"
. If not given, the grid will have no headers.shrink_to_terminal
: WhenTrue
,griddy
will limit column widths so that the total width of the output will fit within the terminal.margin
: When shrinking to the terminal,griddy
will try to maximize the output width such thatterminal_width - margin < output_width < terminal_width
. The larger this value, the larger the acceptable output width and, likely, the faster this function will return. Note:griddy
will, internally, increase the margin when necessary to avoid getting stuck in an infinite loop.table_format
: The grid asthetic. See thetabulate
package for a full list of options.disable_numparse
: Turn off treating and aligning numbers differently from non-numbers.