Skip to content

Commit 1ed97d1

Browse files
committed
Refactoring header row
1 parent 592bfa0 commit 1ed97d1

File tree

2 files changed

+117
-87
lines changed

2 files changed

+117
-87
lines changed

table2ascii/__init__.py

Lines changed: 114 additions & 84 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,21 @@
11
from typing import List
2+
from math import floor, ceil
3+
4+
# constants
5+
ALIGN_LEFT = 0
6+
ALIGN_CENTER = 1
7+
ALIGN_RIGHT = 2
28

39

410
class TableToAscii:
5-
def __init__(
6-
self,
7-
header_row: List[str],
8-
body: List[List[str]],
9-
footer_row: List[str],
10-
):
11-
self.header_row = header_row
12-
self.body = body
13-
self.footer_row = footer_row
14-
self.cell_width = 5
11+
"""Class used to convert a 2D Python table to ASCII text"""
12+
13+
def __init__(self, header_row: List, body: List[List], footer_row: List):
14+
self.__header_row = header_row
15+
self.__body = body
16+
self.__footer_row = footer_row
17+
self.__cell_width = 5 # ! TODO: Remove
18+
self.__cell_widths = [5, 5, 5, 5, 5] # TODO: make this automatic
1519
"""
1620
╔═════╦═══════════════════════╗
1721
║ # ║ G H R S ║
@@ -32,78 +36,103 @@ def __init__(
3236
i11111j11111k11111k11111k11111l
3337
"""
3438
self.parts = {
35-
"top_left_corner": "╔", # 0
36-
"top_bottom_edge": "═", # 1
37-
"first_col_top_tee": "╦", # 2
38-
"top_tee": "═", # 3
39-
"top_right_corner": "╗", # 4
40-
"left_right_edge": "║", # 5
41-
"first_col_sep": "║", # 6
42-
"middle_edge": " ", # 7
43-
"header_left_tee": "╟", # 8
44-
"header_row_sep": "─", # 9
45-
"first_col_header_cross": "╫", # a
46-
"header_row_cross": "─", # b
47-
"right_tee": "╢", # c
48-
"footer_left_tee": "╟", # d
49-
"footer_row_sep": "─", # e
50-
"first_col_footer_cross": "╫", # f
51-
"footer_row_cross": "─", # g
52-
"bottom_left_corner": "╚", # i
53-
"first_col_bottom_tee": "╩", # j
54-
"bottom_tee": "═", # k
55-
"bottom_right_corner": "╝", # l
39+
"top_left_corner": "╔", # 0
40+
"top_and_bottom_edge": "═", # 1
41+
"first_col_top_tee": "╦", # 2
42+
"top_tee": "═", # 3
43+
"top_right_corner": "╗", # 4
44+
"left_and_right_edge": "║", # 5
45+
"first_col_sep": "║", # 6
46+
"middle_edge": " ", # 7
47+
"header_left_tee": "╟", # 8
48+
"header_row_sep": "─", # 9
49+
"first_col_header_cross": "╫", # a
50+
"header_row_cross": "─", # b
51+
"right_tee": "╢", # c
52+
"footer_left_tee": "╟", # d
53+
"footer_row_sep": "─", # e
54+
"first_col_footer_cross": "╫", # f
55+
"footer_row_cross": "─", # g
56+
"bottom_left_corner": "╚", # i
57+
"first_col_bottom_tee": "╩", # j
58+
"bottom_tee": "═", # k
59+
"bottom_right_corner": "╝", # l
5660
}
5761

62+
def __pad(self, text: str, width: int, alignment: int = ALIGN_CENTER):
63+
if alignment == ALIGN_LEFT:
64+
return f" {text} " + (" " * (width - len(text) - 2))
65+
if alignment == ALIGN_CENTER:
66+
before = " " * floor((width - len(text) - 2) / 2)
67+
after = " " * ceil((width - len(text) - 2) / 2)
68+
return before + f" {text} " + after
69+
if alignment == ALIGN_RIGHT:
70+
return (" " * (width - len(text) - 2)) + f" {text} "
71+
raise ValueError(f"The value '{alignment}' is not valid for alignment.")
72+
73+
def __top_edge_to_ascii(self) -> str:
74+
"""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
88+
89+
def __header_row_to_ascii(self) -> str:
90+
"""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:])
101+
)
102+
# add right edge of the table
103+
output += self.parts["left_and_right_edge"]
104+
return output
105+
106+
def __header_sep_to_ascii(self) -> str:
107+
"""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"]
120+
return output
121+
58122
def to_ascii(self) -> str:
59-
cols = len(self.header_row)
123+
cols = len(self.__header_row)
60124
# create table header
61125
table = [
62-
# ╔
63-
self.parts["top_left_corner"]
64-
# ═════╦
65-
+ self.parts["top_bottom_edge"] * self.cell_width + self.parts["first_col_top_tee"]
66-
#
67-
+ (
68-
(self.parts["top_bottom_edge"] * self.cell_width + self.parts["top_tee"])
69-
* (cols - 1)
70-
)[0:-1]
71-
# ╗
72-
+ self.parts["top_right_corner"],
73-
# ║
74-
self.parts["left_right_edge"]
75-
# # ║
76-
+ f" {self.header_row[0]} " + self.parts["first_col_sep"]
77-
# G H R S
78-
+ self.parts["middle_edge"].join(
79-
" " + val + " " for val in self.header_row[1:]
80-
)
81-
# ║
82-
+ self.parts["left_right_edge"],
83-
# ╟
84-
self.parts["header_left_tee"]
85-
# ─────╫
86-
+ (
87-
self.parts["header_row_sep"] * self.cell_width
88-
+ self.parts["first_col_header_cross"]
89-
)
90-
# ───────────────────────
91-
+ (
92-
(
93-
self.parts["header_row_sep"] * self.cell_width
94-
+ self.parts["header_row_cross"]
95-
)
96-
* (cols - 1)
97-
)[0:-1]
98-
# ╢
99-
+ self.parts["right_tee"],
126+
self.__top_edge_to_ascii(),
127+
self.__header_row_to_ascii(),
128+
self.__header_sep_to_ascii(),
100129
]
101130
# add table body
102-
for p in self.body:
131+
for p in self.__body:
103132
# add table row
104133
table += [
105134
# ║
106-
self.parts["left_right_edge"]
135+
self.parts["left_and_right_edge"]
107136
+
108137
# 1 ║
109138
f" {p[0]} "
@@ -113,45 +142,48 @@ def to_ascii(self) -> str:
113142
f"{p[i].rjust(4)} " for i in range(1, cols)
114143
)
115144
# ║
116-
+ self.parts["left_right_edge"]
145+
+ self.parts["left_and_right_edge"]
117146
]
118147
# footer row
119148
table += [
120149
# ╟
121150
self.parts["footer_left_tee"]
122151
# ─────╫
123152
+ (
124-
self.parts["footer_row_sep"] * self.cell_width
153+
self.parts["footer_row_sep"] * self.__cell_width
125154
+ self.parts["first_col_footer_cross"]
126155
)
127156
# ───────────────────────
128157
+ (
129158
(
130-
self.parts["footer_row_sep"] * self.cell_width
159+
self.parts["footer_row_sep"] * self.__cell_width
131160
+ self.parts["footer_row_cross"]
132161
)
133162
* (cols - 1)
134163
)[0:-1]
135164
# ╢
136165
+ self.parts["right_tee"],
137166
# ║
138-
self.parts["left_right_edge"]
167+
self.parts["left_and_right_edge"]
139168
# SUM ║
140-
+ f"{self.footer_row[0].rjust(4)} " + self.parts["first_col_sep"]
169+
+ f"{self.__footer_row[0].rjust(4)} " + self.parts["first_col_sep"]
141170
# 120 ║ 120 ║ 120 ║ 120 ║
142171
+ self.parts["middle_edge"].join(
143-
f"{self.footer_row[i].rjust(4)} " for i in range(1, cols)
172+
f"{self.__footer_row[i].rjust(4)} " for i in range(1, cols)
144173
)
145174
# ║
146-
+ self.parts["left_right_edge"],
175+
+ self.parts["left_and_right_edge"],
147176
# ╚
148177
self.parts["bottom_left_corner"]
149178
# ═════╩
150-
+ self.parts["top_bottom_edge"] * self.cell_width
179+
+ self.parts["top_and_bottom_edge"] * self.__cell_width
151180
+ self.parts["first_col_bottom_tee"]
152181
# ════════════════════════
153182
+ (
154-
(self.parts["top_bottom_edge"] * self.cell_width + self.parts["bottom_tee"])
183+
(
184+
self.parts["top_and_bottom_edge"] * self.__cell_width
185+
+ self.parts["bottom_tee"]
186+
)
155187
* (cols - 1)
156188
)[0:-1]
157189
# ╗
@@ -160,9 +192,7 @@ def to_ascii(self) -> str:
160192
return "\n".join(table)
161193

162194

163-
def table2ascii(
164-
header_row: List[str], body: List[List[str]], footer_row: List[str]
165-
) -> str:
195+
def table2ascii(header_row: List, body: List[List], footer_row: List) -> str:
166196
"""Convert a 2D Python table to ASCII text
167197
#TODO: add param documentation
168198
"""

tests/test_convert.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,9 @@
33

44
def test_normal():
55
text = t2a(
6-
["#", "G", "H", "R", "S"],
7-
[["1", "30", "40", "35", "30"], ["2", "30", "40", "35", "30"]],
8-
["SUM", "130", "140", "135", "130"],
6+
header_row=["#", "G", "H", "R", "S"],
7+
body=[["1", "30", "40", "35", "30"], ["2", "30", "40", "35", "30"]],
8+
footer_row=["SUM", "130", "140", "135", "130"],
99
)
1010
assert text == (
1111
"╔═════╦═══════════════════════╗\n"

0 commit comments

Comments
 (0)