44from typing import List , Optional , Union
55
66
7- @dataclass
8- class Options :
9- """Class for storing options that the user sets"""
10-
11- first_col_heading : bool = False
12- last_col_heading : bool = False
13-
14-
157class Alignment (enum .Enum ):
168 """Enum for alignment types"""
179
@@ -20,57 +12,63 @@ class Alignment(enum.Enum):
2012 RIGHT = 2
2113
2214
15+ @dataclass
16+ class Options :
17+ """Class for storing options that the user sets"""
18+
19+ header : Optional [List ] = None
20+ body : Optional [List [List ]] = None
21+ footer : Optional [List ] = None
22+ first_col_heading : bool = False
23+ last_col_heading : bool = False
24+ column_widths : Optional [List [int ]] = None
25+ alignments : Optional [List [Alignment ]] = None
26+
27+
2328class TableToAscii :
2429 """Class used to convert a 2D Python table to ASCII text"""
2530
26- def __init__ (
27- self ,
28- header : Optional [List ],
29- body : Optional [List [List ]],
30- footer : Optional [List ],
31- column_widths : Optional [List [int ]],
32- alignments : Optional [List [Alignment ]],
33- options : Options ,
34- ):
31+ def __init__ (self , options : Options ):
3532 """Validate arguments and initialize fields"""
3633 # initialize fields
37- self .__header = header
38- self .__body = body
39- self .__footer = footer
40- self .__options = options
34+ self .__header = options .header
35+ self .__body = options .body
36+ self .__footer = options .footer
37+ self .__first_col_heading = options .first_col_heading
38+ self .__last_col_heading = options .last_col_heading
4139
4240 # calculate number of columns
4341 self .__columns = self .__count_columns ()
4442
4543 # check if footer has a different number of columns
46- if footer and len (footer ) != self .__columns :
44+ if options . footer and len (options . footer ) != self .__columns :
4745 raise ValueError (
4846 "Footer must have the same number of columns as the other rows"
4947 )
5048 # check if any rows in body have a different number of columns
51- if body and tuple ( filter ( lambda r : len (r ) != self .__columns , body ) ):
49+ if options . body and any ( len (row ) != self .__columns for row in options . body ):
5250 raise ValueError (
5351 "All rows in body must have the same number of columns as the other rows"
5452 )
5553
5654 # calculate or use given column widths
57- self .__column_widths = column_widths or self .__auto_column_widths ()
55+ self .__column_widths = options . column_widths or self .__auto_column_widths ()
5856
5957 # check if column widths specified have a different number of columns
60- if column_widths and len (column_widths ) != self .__columns :
58+ if options . column_widths and len (options . column_widths ) != self .__columns :
6159 raise ValueError (
6260 "Length of `column_widths` list must equal the number of columns"
6361 )
6462 # check if column widths are not all at least 2
65- if column_widths and min (column_widths ) < 2 :
63+ if options . column_widths and min (options . column_widths ) < 2 :
6664 raise ValueError (
6765 "All values in `column_widths` must be greater than or equal to 2"
6866 )
6967
70- self .__alignments = alignments or [Alignment .CENTER ] * self .__columns
68+ self .__alignments = options . alignments or [Alignment .CENTER ] * self .__columns
7169
7270 # check if alignments specified have a different number of columns
73- if alignments and len (alignments ) != self .__columns :
71+ if options . alignments and len (options . alignments ) != self .__columns :
7472 raise ValueError (
7573 "Length of `alignments` list must equal the number of columns"
7674 )
@@ -162,8 +160,6 @@ def __row_to_ascii(
162160 filler : Union [str , List ],
163161 ) -> str :
164162 """Assembles a row of the ascii table"""
165- first_heading = self .__options .first_col_heading
166- last_heading = self .__options .last_col_heading
167163 # left edge of the row
168164 output = left_edge
169165 # add columns
@@ -180,8 +176,11 @@ def __row_to_ascii(
180176 )
181177 # column seperator
182178 sep = column_seperator
183- if (i == 0 and first_heading ) or (i == self .__columns - 2 and last_heading ):
184- # use column heading if option is specified
179+ if i == 0 and self .__first_col_heading :
180+ # use column heading if first column option is specified
181+ sep = heading_col_sep
182+ elif i == self .__columns - 2 and self .__last_col_heading :
183+ # use column heading if last column option is specified
185184 sep = heading_col_sep
186185 elif i == self .__columns - 1 :
187186 # replace last seperator with symbol for edge of the row
@@ -250,16 +249,16 @@ def __footer_sep_to_ascii(self) -> str:
250249 )
251250
252251 def __body_to_ascii (self ) -> str :
253- output : str = ""
254- for row in self .__body :
255- output += self .__row_to_ascii (
252+ return "" .join (
253+ self .__row_to_ascii (
256254 left_edge = self .__parts ["left_and_right_edge" ],
257255 heading_col_sep = self .__parts ["heading_col_sep" ],
258256 column_seperator = self .__parts ["middle_edge" ],
259257 right_edge = self .__parts ["left_and_right_edge" ],
260258 filler = row ,
261259 )
262- return output
260+ for row in self .__body
261+ )
263262
264263 def to_ascii (self ) -> str :
265264 # top row of table
@@ -281,14 +280,7 @@ def to_ascii(self) -> str:
281280 return table
282281
283282
284- def table2ascii (
285- header : Optional [List ] = None ,
286- body : Optional [List [List ]] = None ,
287- footer : Optional [List ] = None ,
288- column_widths : Optional [List [int ]] = None ,
289- alignments : Optional [List [Alignment ]] = None ,
290- ** options ,
291- ) -> str :
283+ def table2ascii (** options ) -> str :
292284 """Convert a 2D Python table to ASCII text
293285
294286 ### Arguments
@@ -297,11 +289,7 @@ def table2ascii(
297289 :param footer: :class:`Optional[List]` List of column values in the table's footer row
298290 :param column_widths: :class:`Optional[List[int]]` List of widths in characters for each column (defaults to auto-sizing)
299291 :param alignments: :class:`Optional[List[Alignment]]` List of alignments (ex. `[Alignment.LEFT, Alignment.CENTER, Alignment.RIGHT]`)
300-
301- ### Additional options
302292 :param first_col_heading: :class:`Optional[bool]` Whether to add a header column separator after the first column
303293 :param last_col_heading: :class:`Optional[bool]` Whether to add a header column separator before the last column
304294 """
305- return TableToAscii (
306- header , body , footer , column_widths , alignments , Options (** options )
307- ).to_ascii ()
295+ return TableToAscii (Options (** options )).to_ascii ()
0 commit comments