@@ -19,8 +19,7 @@ def __init__(
1919 footer : list [SupportsStr ] | None ,
2020 options : Options ,
2121 ):
22- """
23- Validate arguments and initialize fields
22+ """Validate arguments and initialize fields
2423
2524 Args:
2625 header: The values in the header of the table
@@ -50,22 +49,7 @@ def __init__(
5049 )
5150
5251 # calculate or use given column widths
53- self .__column_widths = self .__auto_column_widths ()
54- if options .column_widths :
55- # check that the right number of columns were specified
56- if len (options .column_widths ) != self .__columns :
57- raise ValueError ("Length of `column_widths` list must equal the number of columns" )
58- # check that each column is at least as large as the minimum size
59- for i in range (len (options .column_widths )):
60- option = options .column_widths [i ]
61- minimum = self .__column_widths [i ]
62- if option is None :
63- option = minimum
64- elif option < minimum :
65- raise ValueError (
66- f"The value at index { i } of `column_widths` is { option } which is less than the minimum { minimum } ."
67- )
68- self .__column_widths [i ] = option
52+ self .__column_widths = self .__calculate_column_widths (options .column_widths )
6953
7054 self .__alignments = options .alignments or [Alignment .CENTER ] * self .__columns
7155
@@ -78,9 +62,7 @@ def __init__(
7862 raise ValueError ("Cell padding must be greater than or equal to 0" )
7963
8064 def __count_columns (self ) -> int :
81- """
82- Get the number of columns in the table based on the
83- provided header, footer, and body lists.
65+ """Get the number of columns in the table based on the provided header, footer, and body lists.
8466
8567 Returns:
8668 The number of columns in the table
@@ -94,9 +76,8 @@ def __count_columns(self) -> int:
9476 return 0
9577
9678 def __auto_column_widths (self ) -> list [int ]:
97- """
98- Get the minimum number of characters needed for the values in
99- each column in the table with 1 space of padding on each side.
79+ """Get the minimum number of characters needed for the values in each column in the table
80+ with 1 space of padding on each side.
10081
10182 Returns:
10283 The minimum number of characters needed for each column
@@ -118,9 +99,35 @@ def widest_line(value: SupportsStr) -> int:
11899 column_widths .append (max (header_size , body_size , footer_size ) + self .__cell_padding * 2 )
119100 return column_widths
120101
121- def __pad (self , cell_value : SupportsStr , width : int , alignment : Alignment ) -> str :
102+ def __calculate_column_widths (self , user_column_widths : list [int | None ] | None ) -> list [int ]:
103+ """Calculate the width of each column in the table based on the cell values and provided column widths.
104+
105+ Args:
106+ user_column_widths: The user specified column widths
107+
108+ Returns:
109+ The width of each column in the table
122110 """
123- Pad a string of text to a given width with specified alignment
111+ column_widths = self .__auto_column_widths ()
112+ if user_column_widths :
113+ # check that the right number of columns were specified
114+ if len (user_column_widths ) != self .__columns :
115+ raise ValueError ("Length of `column_widths` list must equal the number of columns" )
116+ # check that each column is at least as large as the minimum size
117+ for i in range (len (user_column_widths )):
118+ option = user_column_widths [i ]
119+ minimum = column_widths [i ]
120+ if option is None :
121+ option = minimum
122+ elif option < minimum :
123+ raise ValueError (
124+ f"The value at index { i } of `column_widths` is { option } which is less than the minimum { minimum } ."
125+ )
126+ column_widths [i ] = option
127+ return column_widths
128+
129+ def __pad (self , cell_value : SupportsStr , width : int , alignment : Alignment ) -> str :
130+ """Pad a string of text to a given width with specified alignment
124131
125132 Args:
126133 cell_value: The text in the cell to pad
@@ -154,8 +161,7 @@ def __row_to_ascii(
154161 right_edge : str ,
155162 filler : str | list [SupportsStr ],
156163 ) -> str :
157- """
158- Assembles a line of text in the ascii table
164+ """Assembles a line of text in the ascii table
159165
160166 Returns:
161167 The line in the ascii table
@@ -165,50 +171,96 @@ def __row_to_ascii(
165171 num_lines = max (len (str (cell ).splitlines ()) for cell in filler ) or 1
166172 # repeat for each line of text in the cell
167173 for line_index in range (num_lines ):
168- # left edge of the row
169- output += left_edge
170- # add columns
171- for col_index in range (self .__columns ):
172- # content between separators
173- col_content = ""
174- # if filler is a separator character, repeat it for the full width of the column
175- if isinstance (filler , str ):
176- col_content = filler * self .__column_widths [col_index ]
177- # otherwise, use the text from the corresponding column in the filler list
178- else :
179- # get the text of the current line in the cell
180- # if there are fewer lines in the current cell than others, empty string is used
181- col_lines = str (filler [col_index ]).splitlines ()
182- if line_index < len (col_lines ):
183- col_content = col_lines [line_index ]
184- # pad the text to the width of the column using the alignment
185- col_content = self .__pad (
186- col_content ,
187- self .__column_widths [col_index ],
188- self .__alignments [col_index ],
189- )
190- output += col_content
191- # column separator
192- sep = column_separator
193- if col_index == 0 and self .__first_col_heading :
194- # use column heading if first column option is specified
195- sep = heading_col_sep
196- elif col_index == self .__columns - 2 and self .__last_col_heading :
197- # use column heading if last column option is specified
198- sep = heading_col_sep
199- elif col_index == self .__columns - 1 :
200- # replace last separator with symbol for edge of the row
201- sep = right_edge
202- output += sep
203- output += "\n "
204- # don't use separation row if it's only space
205- if isinstance (filler , str ) and output .strip () == "" :
206- output = ""
174+ output += self .__line_in_row_to_ascii (
175+ line_index ,
176+ left_edge ,
177+ heading_col_sep ,
178+ column_separator ,
179+ right_edge ,
180+ filler ,
181+ )
182+ # don't use separation row if it's only space
183+ if isinstance (filler , str ) and output .strip () == "" :
184+ output = ""
207185 return output
208186
209- def __top_edge_to_ascii (self ) -> str :
187+ def __line_in_row_to_ascii (
188+ self ,
189+ line_index : int ,
190+ left_edge : str ,
191+ heading_col_sep : str ,
192+ column_separator : str ,
193+ right_edge : str ,
194+ filler : str | list [SupportsStr ],
195+ ) -> str :
196+ """Assembles a line of text in the ascii table
197+
198+ Returns:
199+ The line in the ascii table
200+ """
201+ output = left_edge
202+ # add columns
203+ for col_index in range (self .__columns ):
204+ output += self .__line_in_cell_column_to_ascii (
205+ line_index ,
206+ col_index ,
207+ heading_col_sep ,
208+ column_separator ,
209+ right_edge ,
210+ filler ,
211+ )
212+ output += "\n "
213+ return output
214+
215+ def __line_in_cell_column_to_ascii (
216+ self ,
217+ line_index : int ,
218+ col_index : int ,
219+ heading_col_sep : str ,
220+ column_separator : str ,
221+ right_edge : str ,
222+ filler : str | list [SupportsStr ],
223+ ) -> str :
224+ """Assembles a column of text in the ascii table
225+
226+ Returns:
227+ The column in the ascii table
210228 """
211- Assembles the top edge of the ascii table
229+ output = ""
230+ # content between separators
231+ col_content = ""
232+ # if filler is a separator character, repeat it for the full width of the column
233+ if isinstance (filler , str ):
234+ col_content = filler * self .__column_widths [col_index ]
235+ # otherwise, use the text from the corresponding column in the filler list
236+ else :
237+ # get the text of the current line in the cell
238+ # if there are fewer lines in the current cell than others, empty string is used
239+ col_lines = str (filler [col_index ]).splitlines ()
240+ if line_index < len (col_lines ):
241+ col_content = col_lines [line_index ]
242+ # pad the text to the width of the column using the alignment
243+ col_content = self .__pad (
244+ col_content ,
245+ self .__column_widths [col_index ],
246+ self .__alignments [col_index ],
247+ )
248+ output += col_content
249+ # column separator
250+ sep = column_separator
251+ if col_index == 0 and self .__first_col_heading :
252+ # use column heading if first column option is specified
253+ sep = heading_col_sep
254+ elif col_index == self .__columns - 2 and self .__last_col_heading :
255+ # use column heading if last column option is specified
256+ sep = heading_col_sep
257+ elif col_index == self .__columns - 1 :
258+ # replace last separator with symbol for edge of the row
259+ sep = right_edge
260+ return output + sep
261+
262+ def __top_edge_to_ascii (self ) -> str :
263+ """Assembles the top edge of the ascii table
212264
213265 Returns:
214266 The top edge of the ascii table
@@ -222,8 +274,7 @@ def __top_edge_to_ascii(self) -> str:
222274 )
223275
224276 def __bottom_edge_to_ascii (self ) -> str :
225- """
226- Assembles the bottom edge of the ascii table
277+ """Assembles the bottom edge of the ascii table
227278
228279 Returns:
229280 The bottom edge of the ascii table
@@ -237,8 +288,7 @@ def __bottom_edge_to_ascii(self) -> str:
237288 )
238289
239290 def __heading_row_to_ascii (self , row : list [SupportsStr ]) -> str :
240- """
241- Assembles the header or footer row line of the ascii table
291+ """Assembles the header or footer row line of the ascii table
242292
243293 Returns:
244294 The header or footer row line of the ascii table
@@ -252,8 +302,7 @@ def __heading_row_to_ascii(self, row: list[SupportsStr]) -> str:
252302 )
253303
254304 def __heading_sep_to_ascii (self ) -> str :
255- """
256- Assembles the separator below the header or above footer of the ascii table
305+ """Assembles the separator below the header or above footer of the ascii table
257306
258307 Returns:
259308 The separator line
@@ -267,8 +316,7 @@ def __heading_sep_to_ascii(self) -> str:
267316 )
268317
269318 def __body_to_ascii (self , body : list [list [SupportsStr ]]) -> str :
270- """
271- Assembles the body of the ascii table
319+ """Assembles the body of the ascii table
272320
273321 Returns:
274322 The body of the ascii table
@@ -292,8 +340,7 @@ def __body_to_ascii(self, body: list[list[SupportsStr]]) -> str:
292340 )
293341
294342 def to_ascii (self ) -> str :
295- """
296- Generates a formatted ASCII table
343+ """Generates a formatted ASCII table
297344
298345 Returns:
299346 The generated ASCII table
@@ -329,8 +376,7 @@ def table2ascii(
329376 cell_padding : int = 1 ,
330377 style : TableStyle = PresetStyle .double_thin_compact ,
331378) -> str :
332- """
333- Convert a 2D Python table to ASCII text
379+ """Convert a 2D Python table to ASCII text
334380
335381 Args:
336382 header: List of column values in the table's header row. All values should be :class:`str`
0 commit comments