@@ -19,8 +19,7 @@ def __init__(
19
19
footer : list [SupportsStr ] | None ,
20
20
options : Options ,
21
21
):
22
- """
23
- Validate arguments and initialize fields
22
+ """Validate arguments and initialize fields
24
23
25
24
Args:
26
25
header: The values in the header of the table
@@ -50,22 +49,7 @@ def __init__(
50
49
)
51
50
52
51
# 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 )
69
53
70
54
self .__alignments = options .alignments or [Alignment .CENTER ] * self .__columns
71
55
@@ -78,9 +62,7 @@ def __init__(
78
62
raise ValueError ("Cell padding must be greater than or equal to 0" )
79
63
80
64
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.
84
66
85
67
Returns:
86
68
The number of columns in the table
@@ -94,9 +76,8 @@ def __count_columns(self) -> int:
94
76
return 0
95
77
96
78
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.
100
81
101
82
Returns:
102
83
The minimum number of characters needed for each column
@@ -118,9 +99,35 @@ def widest_line(value: SupportsStr) -> int:
118
99
column_widths .append (max (header_size , body_size , footer_size ) + self .__cell_padding * 2 )
119
100
return column_widths
120
101
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
122
110
"""
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
124
131
125
132
Args:
126
133
cell_value: The text in the cell to pad
@@ -154,8 +161,7 @@ def __row_to_ascii(
154
161
right_edge : str ,
155
162
filler : str | list [SupportsStr ],
156
163
) -> str :
157
- """
158
- Assembles a line of text in the ascii table
164
+ """Assembles a line of text in the ascii table
159
165
160
166
Returns:
161
167
The line in the ascii table
@@ -165,50 +171,96 @@ def __row_to_ascii(
165
171
num_lines = max (len (str (cell ).splitlines ()) for cell in filler ) or 1
166
172
# repeat for each line of text in the cell
167
173
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 = ""
207
185
return output
208
186
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
210
228
"""
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
212
264
213
265
Returns:
214
266
The top edge of the ascii table
@@ -222,8 +274,7 @@ def __top_edge_to_ascii(self) -> str:
222
274
)
223
275
224
276
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
227
278
228
279
Returns:
229
280
The bottom edge of the ascii table
@@ -237,8 +288,7 @@ def __bottom_edge_to_ascii(self) -> str:
237
288
)
238
289
239
290
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
242
292
243
293
Returns:
244
294
The header or footer row line of the ascii table
@@ -252,8 +302,7 @@ def __heading_row_to_ascii(self, row: list[SupportsStr]) -> str:
252
302
)
253
303
254
304
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
257
306
258
307
Returns:
259
308
The separator line
@@ -267,8 +316,7 @@ def __heading_sep_to_ascii(self) -> str:
267
316
)
268
317
269
318
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
272
320
273
321
Returns:
274
322
The body of the ascii table
@@ -292,8 +340,7 @@ def __body_to_ascii(self, body: list[list[SupportsStr]]) -> str:
292
340
)
293
341
294
342
def to_ascii (self ) -> str :
295
- """
296
- Generates a formatted ASCII table
343
+ """Generates a formatted ASCII table
297
344
298
345
Returns:
299
346
The generated ASCII table
@@ -329,8 +376,7 @@ def table2ascii(
329
376
cell_padding : int = 1 ,
330
377
style : TableStyle = PresetStyle .double_thin_compact ,
331
378
) -> str :
332
- """
333
- Convert a 2D Python table to ASCII text
379
+ """Convert a 2D Python table to ASCII text
334
380
335
381
Args:
336
382
header: List of column values in the table's header row. All values should be :class:`str`
0 commit comments