@@ -28,29 +28,41 @@ def __init__(
2828 header : Optional [List ],
2929 body : Optional [List [List ]],
3030 footer : Optional [List ],
31+ column_widths : Optional [List [int ]],
3132 options : Options ,
3233 ):
3334 """Validate arguments and initialize fields"""
34- # check if columns in header are different from footer
35- if header and footer and len (header ) != len (footer ):
36- raise ValueError ("Header row and footer row must have the same length" )
37- # check if columns in header are different from body
38- if header and body and len (body ) > 0 and len (header ) != len (body [0 ]):
39- raise ValueError ("Header row and body rows must have the same length" )
40- # check if columns in header are different from body
41- if footer and body and len (body ) > 0 and len (footer ) != len (body [0 ]):
42- raise ValueError ("Footer row and body rows must have the same length" )
43- # check if any rows in body have a different number of columns
44- if body and len (body ) and tuple (filter (lambda r : len (r ) != len (body [0 ]), body )):
45- raise ValueError ("All rows in body must have the same length" )
46-
4735 # initialize fields
4836 self .__header = header
4937 self .__body = body
5038 self .__footer = footer
5139 self .__options = options
5240 self .__columns = self .__count_columns ()
53- self .__cell_widths = self .__get_column_widths ()
41+
42+ # check if footer has a different number of columns
43+ if footer and len (footer ) != self .__columns :
44+ raise ValueError (
45+ "Footer must have the same number of columns as the other rows"
46+ )
47+ # check if any rows in body have a different number of columns
48+ if body and tuple (filter (lambda r : len (r ) != self .__columns , body )):
49+ raise ValueError (
50+ "All rows in body must have the same number of columns as the other rows"
51+ )
52+
53+ # calculate column widths
54+ self .__column_widths = column_widths or self .__auto_column_widths ()
55+
56+ # check if column widths specified have a different number of columns
57+ if column_widths and len (column_widths ) != self .__columns :
58+ raise ValueError (
59+ "Length of `column_widths` list must equal the number of columns"
60+ )
61+ # check if column widths are not all at least 2
62+ if column_widths and min (column_widths ) < 2 :
63+ raise ValueError (
64+ "All values in `column_widths` must be greater than or equal to 2"
65+ )
5466
5567 """
5668 ╔═════╦═══════════════════════╗ ABBBBBCBBBBBDBBBBBDBBBBBDBBBBBE
@@ -99,11 +111,11 @@ def __count_columns(self) -> int:
99111 return len (self .__body [0 ])
100112 return 0
101113
102- def __get_column_widths (self ) -> List [int ]:
114+ def __auto_column_widths (self ) -> List [int ]:
103115 """Get the minimum number of characters needed for the values
104116 in each column in the table with 1 space of padding on each side.
105117 """
106- col_counts = []
118+ column_widths = []
107119 for i in range (self .__columns ):
108120 # number of characters in column of i of header, each body row, and footer
109121 header_size = len (self .__header [i ]) if self .__header else 0
@@ -112,8 +124,8 @@ def __get_column_widths(self) -> List[int]:
112124 )
113125 footer_size = len (self .__footer [i ]) if self .__footer else 0
114126 # get the max and add 2 for padding each side with a space
115- col_counts .append (max (header_size , * body_size , footer_size ) + 2 )
116- return col_counts
127+ column_widths .append (max (header_size , * body_size , footer_size ) + 2 )
128+ return column_widths
117129
118130 def __pad (self , text : str , width : int , alignment : Alignment = Alignment .CENTER ):
119131 """Pad a string of text to a given width with specified alignment"""
@@ -148,10 +160,10 @@ def __row_to_ascii(
148160 # content between separators
149161 output += (
150162 # edge or row separator if filler is a specific character
151- filler * self .__cell_widths [i ]
163+ filler * self .__column_widths [i ]
152164 if isinstance (filler , str )
153165 # otherwise, use the column content
154- else self .__pad (str (filler [i ]), self .__cell_widths [i ])
166+ else self .__pad (str (filler [i ]), self .__column_widths [i ])
155167 )
156168 # column seperator
157169 sep = column_seperator
@@ -260,6 +272,7 @@ def table2ascii(
260272 header : Optional [List ] = None ,
261273 body : Optional [List [List ]] = None ,
262274 footer : Optional [List ] = None ,
275+ column_widths : Optional [List [int ]] = None ,
263276 ** options ,
264277) -> str :
265278 """Convert a 2D Python table to ASCII text
@@ -268,5 +281,9 @@ def table2ascii(
268281 :param header: :class:`Optional[List]` List of column values in the table's header row
269282 :param body: :class:`Optional[List[List]]` 2-dimensional list of values in the table's body
270283 :param footer: :class:`Optional[List]` List of column values in the table's footer row
284+ :param column_widths: :class:`Optional[List[int]]` List of widths in characters for each column (defaults to auto-sizing)
285+ :param footer: :class:`Optional[List]` List of column values in the table's footer row
271286 """
272- return TableToAscii (header , body , footer , Options (** options )).to_ascii ()
287+ return TableToAscii (
288+ header , body , footer , column_widths , Options (** options )
289+ ).to_ascii ()
0 commit comments