1- from typing import List
1+ from typing import List , Union
22from math import floor , ceil
33
44# constants
@@ -14,26 +14,17 @@ def __init__(self, header_row: List, body: List[List], footer_row: List):
1414 self .__header_row = header_row
1515 self .__body = body
1616 self .__footer_row = footer_row
17- self .__cell_width = 5 # ! TODO: Remove
1817 self .__cell_widths = [5 , 5 , 5 , 5 , 5 ] # TODO: make this automatic
18+
1919 """
20- ╔═════╦═══════════════════════╗
21- ║ # ║ G H R S ║
22- ╟─────╫───────────────────────╢
23- ║ 1 ║ 30 40 35 30 ║
24- ║ 2 ║ 30 40 35 30 ║
25- ╟─────╫───────────────────────╢
26- ║ SUM ║ 130 140 135 130 ║
27- ╚═════╩═══════════════════════╝
28-
29- 0111112111113111113111113111114
30- 5 6 7 7 7 5
31- 899999a99999b99999b99999b99999c
32- 5 6 7 7 7 5
33- 5 6 7 7 7 5
34- deeeeefeeeeegeeeeegeeeeegeeeeeh
35- 5 6 7 7 7 5
36- i11111j11111k11111k11111k11111l
20+ ╔═════╦═══════════════════════╗ 0111112111113111113111113111114
21+ ║ # ║ G H R S ║ 5 6 7 7 7 5
22+ ╟─────╫───────────────────────╢ 899999a99999b99999b99999b99999c
23+ ║ 1 ║ 30 40 35 30 ║ 5 6 7 7 7 5
24+ ║ 2 ║ 30 40 35 30 ║ 5 6 7 7 7 5
25+ ╟─────╫───────────────────────╢ deeeeefeeeeegeeeeegeeeeegeeeeeh
26+ ║ SUM ║ 130 140 135 130 ║ 5 6 7 7 7 5
27+ ╚═════╩═══════════════════════╝ i11111j11111k11111k11111k11111l
3728 """
3829 self .parts = {
3930 "top_left_corner" : "╔" , # 0
@@ -60,136 +51,138 @@ def __init__(self, header_row: List, body: List[List], footer_row: List):
6051 }
6152
6253 def __pad (self , text : str , width : int , alignment : int = ALIGN_CENTER ):
54+ """Pad a string of text to a given width with specified alignment"""
6355 if alignment == ALIGN_LEFT :
6456 return f" { text } " + (" " * (width - len (text ) - 2 ))
6557 if alignment == ALIGN_CENTER :
66- before = " " * floor ((width - len (text ) - 2 ) / 2 )
67- after = " " * ceil ((width - len (text ) - 2 ) / 2 )
58+ before = " " * ceil ((width - len (text ) - 2 ) / 2 )
59+ after = " " * floor ((width - len (text ) - 2 ) / 2 )
6860 return before + f" { text } " + after
6961 if alignment == ALIGN_RIGHT :
7062 return (" " * (width - len (text ) - 2 )) + f" { text } "
7163 raise ValueError (f"The value '{ alignment } ' is not valid for alignment." )
7264
65+ def __row_to_ascii (
66+ self ,
67+ left : str ,
68+ first_col_sep : str ,
69+ col_sep : str ,
70+ right : str ,
71+ filler : Union [str , List ],
72+ ) -> str :
73+ """Assembles a row of the ascii table"""
74+ # left edge of the row
75+ output : str = left
76+ # content across the first column
77+ output += (
78+ # edge or row separator if filler is specified
79+ filler * self .__cell_widths [0 ]
80+ if isinstance (filler , str )
81+ # otherwise, first column content
82+ else self .__pad (str (filler [0 ]), self .__cell_widths [0 ])
83+ )
84+ # separation of first column from the rest of the table
85+ output += first_col_sep
86+ # add remaining columns
87+ for i in range (1 , len (self .__header_row )):
88+ # content between separators
89+ output += (
90+ # edge or row separator if filler is specified
91+ filler * self .__cell_widths [i ]
92+ if isinstance (filler , str )
93+ # otherwise, column content
94+ else self .__pad (str (filler [i ]), self .__cell_widths [i ])
95+ )
96+ # add a separator
97+ output += col_sep
98+ # replace last seperator with symbol for edge of the row
99+ output = output [0 :- 1 ] + right
100+ return output + "\n "
101+
73102 def __top_edge_to_ascii (self ) -> str :
74103 """Assembles the top edge of the ascii table"""
75- # top-left corner of the table
76- output : str = self .parts ["top_left_corner" ]
77- # top edge above the first column
78- output += self .parts ["top_and_bottom_edge" ] * self .__cell_widths [0 ]
79- # tee separating first column from the rest of the table
80- output += self .parts ["first_col_top_tee" ]
81- # add remaining columns
82- for i in range (len (self .__header_row ) - 1 ):
83- output += self .parts ["top_and_bottom_edge" ] * self .__cell_widths [i ]
84- output += self .parts ["top_tee" ]
85- # replace last top tee with top-right corner
86- output = output [0 :- 1 ] + self .parts ["top_right_corner" ]
87- return output
104+ return self .__row_to_ascii (
105+ left = self .parts ["top_left_corner" ],
106+ first_col_sep = self .parts ["first_col_top_tee" ],
107+ col_sep = self .parts ["top_tee" ],
108+ right = self .parts ["top_right_corner" ],
109+ filler = self .parts ["top_and_bottom_edge" ],
110+ )
111+
112+ def __bottom_edge_to_ascii (self ) -> str :
113+ """Assembles the top edge of the ascii table"""
114+ return self .__row_to_ascii (
115+ left = self .parts ["bottom_left_corner" ],
116+ first_col_sep = self .parts ["first_col_bottom_tee" ],
117+ col_sep = self .parts ["bottom_tee" ],
118+ right = self .parts ["bottom_right_corner" ],
119+ filler = self .parts ["top_and_bottom_edge" ],
120+ )
88121
89122 def __header_row_to_ascii (self ) -> str :
90123 """Assembles the header row line of the ascii table"""
91- # add left edge of table
92- output : str = self .parts ["left_and_right_edge" ]
93- # add first column contents and padding
94- output += self .__pad (str (self .__header_row [0 ]), self .__cell_widths [0 ])
95- # separate first column from the rest of the table
96- output += self .parts ["first_col_sep" ]
97- # add the rest of the headers
98- output += self .parts ["middle_edge" ].join (
99- self .__pad (str (val ), self .__cell_widths [i + 1 ])
100- for i , val in enumerate (self .__header_row [1 :])
124+ return self .__row_to_ascii (
125+ left = self .parts ["left_and_right_edge" ],
126+ first_col_sep = self .parts ["first_col_sep" ],
127+ col_sep = self .parts ["middle_edge" ],
128+ right = self .parts ["left_and_right_edge" ],
129+ filler = self .__header_row ,
130+ )
131+
132+ def __footer_row_to_ascii (self ) -> str :
133+ """Assembles the header row line of the ascii table"""
134+ return self .__row_to_ascii (
135+ left = self .parts ["left_and_right_edge" ],
136+ first_col_sep = self .parts ["first_col_sep" ],
137+ col_sep = self .parts ["middle_edge" ],
138+ right = self .parts ["left_and_right_edge" ],
139+ filler = self .__footer_row ,
101140 )
102- # add right edge of the table
103- output += self .parts ["left_and_right_edge" ]
104- return output
105141
106142 def __header_sep_to_ascii (self ) -> str :
107143 """Assembles the seperator below the header of the ascii table"""
108- # add left edge tee
109- output : str = self .parts ["header_left_tee" ]
110- # top edge above the first column
111- output += self .parts ["header_row_sep" ] * self .__cell_widths [0 ]
112- # tee separating first column from the rest of the table
113- output += self .parts ["first_col_header_cross" ]
114- # add remaining columns
115- for i in range (len (self .__header_row ) - 1 ):
116- output += self .parts ["header_row_sep" ] * self .__cell_widths [i ]
117- output += self .parts ["header_row_cross" ]
118- # replace last top tee with top-right corner
119- output = output [0 :- 1 ] + self .parts ["right_tee" ]
144+ return self .__row_to_ascii (
145+ left = self .parts ["header_left_tee" ],
146+ first_col_sep = self .parts ["first_col_header_cross" ],
147+ col_sep = self .parts ["header_row_cross" ],
148+ right = self .parts ["right_tee" ],
149+ filler = self .parts ["header_row_sep" ],
150+ )
151+
152+ def __footer_sep_to_ascii (self ) -> str :
153+ """Assembles the seperator below the header of the ascii table"""
154+ return self .__row_to_ascii (
155+ left = self .parts ["footer_left_tee" ],
156+ first_col_sep = self .parts ["first_col_footer_cross" ],
157+ col_sep = self .parts ["footer_row_cross" ],
158+ right = self .parts ["right_tee" ],
159+ filler = self .parts ["header_row_sep" ],
160+ )
161+
162+ def __body_to_ascii (self ) -> str :
163+ output : str = ""
164+ for row in self .__body :
165+ output += self .__row_to_ascii (
166+ left = self .parts ["left_and_right_edge" ],
167+ first_col_sep = self .parts ["first_col_sep" ],
168+ col_sep = self .parts ["middle_edge" ],
169+ right = self .parts ["left_and_right_edge" ],
170+ filler = row ,
171+ )
120172 return output
121173
122174 def to_ascii (self ) -> str :
123- cols = len (self .__header_row )
124- # create table header
125- table = [
126- self .__top_edge_to_ascii (),
127- self .__header_row_to_ascii (),
128- self .__header_sep_to_ascii (),
129- ]
175+ # add table header
176+ table : str = self .__top_edge_to_ascii ()
177+ table += self .__header_row_to_ascii ()
178+ table += self .__header_sep_to_ascii ()
130179 # add table body
131- for p in self .__body :
132- # add table row
133- table += [
134- # ║
135- self .parts ["left_and_right_edge" ]
136- +
137- # 1 ║
138- f" { p [0 ]} "
139- + self .parts ["first_col_sep" ]
140- # 40 40 40 40
141- + self .parts ["middle_edge" ].join (
142- f"{ p [i ].rjust (4 )} " for i in range (1 , cols )
143- )
144- # ║
145- + self .parts ["left_and_right_edge" ]
146- ]
147- # footer row
148- table += [
149- # ╟
150- self .parts ["footer_left_tee" ]
151- # ─────╫
152- + (
153- self .parts ["footer_row_sep" ] * self .__cell_width
154- + self .parts ["first_col_footer_cross" ]
155- )
156- # ───────────────────────
157- + (
158- (
159- self .parts ["footer_row_sep" ] * self .__cell_width
160- + self .parts ["footer_row_cross" ]
161- )
162- * (cols - 1 )
163- )[0 :- 1 ]
164- # ╢
165- + self .parts ["right_tee" ],
166- # ║
167- self .parts ["left_and_right_edge" ]
168- # SUM ║
169- + f"{ self .__footer_row [0 ].rjust (4 )} " + self .parts ["first_col_sep" ]
170- # 120 ║ 120 ║ 120 ║ 120 ║
171- + self .parts ["middle_edge" ].join (
172- f"{ self .__footer_row [i ].rjust (4 )} " for i in range (1 , cols )
173- )
174- # ║
175- + self .parts ["left_and_right_edge" ],
176- # ╚
177- self .parts ["bottom_left_corner" ]
178- # ═════╩
179- + self .parts ["top_and_bottom_edge" ] * self .__cell_width
180- + self .parts ["first_col_bottom_tee" ]
181- # ════════════════════════
182- + (
183- (
184- self .parts ["top_and_bottom_edge" ] * self .__cell_width
185- + self .parts ["bottom_tee" ]
186- )
187- * (cols - 1 )
188- )[0 :- 1 ]
189- # ╗
190- + self .parts ["bottom_right_corner" ],
191- ]
192- return "\n " .join (table )
180+ table += self .__body_to_ascii ()
181+ # add table footer
182+ table += self .__footer_sep_to_ascii ()
183+ table += self .__footer_row_to_ascii ()
184+ table += self .__bottom_edge_to_ascii ()
185+ return table
193186
194187
195188def table2ascii (header_row : List , body : List [List ], footer_row : List ) -> str :
0 commit comments