Skip to content

refactor: comment style and reduce nesting complexity #65

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 3 commits into from
Dec 11, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 1 addition & 2 deletions table2ascii/alignment.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,7 @@


class Alignment(Enum):
"""
Enum for text alignment types within a table cell
"""Enum for text alignment types within a table cell

Example::

Expand Down
3 changes: 1 addition & 2 deletions table2ascii/preset_style.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,7 @@


class PresetStyle:
"""
Importable preset styles for more easily selecting a :ref:`TableStyle`.
"""Importable preset styles for more easily selecting a :ref:`TableStyle`.

See the :ref:`Preset Styles<styles>` for more information on the available styles.

Expand Down
6 changes: 2 additions & 4 deletions table2ascii/table_style.py
Original file line number Diff line number Diff line change
Expand Up @@ -61,8 +61,7 @@ class TableStyle:

@classmethod
def from_string(cls, string: str) -> "TableStyle":
"""
Create a TableStyle from a string
"""Create a TableStyle from a string

Args:
string: The string to create the TableStyle from
Expand All @@ -77,8 +76,7 @@ def from_string(cls, string: str) -> "TableStyle":
return cls(*string)

def set(self, **kwargs) -> "TableStyle":
"""
Set attributes of the TableStyle
"""Set attributes of the TableStyle

Args:
kwargs: The attributes to set
Expand Down
208 changes: 127 additions & 81 deletions table2ascii/table_to_ascii.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,7 @@ def __init__(
footer: list[SupportsStr] | None,
options: Options,
):
"""
Validate arguments and initialize fields
"""Validate arguments and initialize fields

Args:
header: The values in the header of the table
Expand Down Expand Up @@ -50,22 +49,7 @@ def __init__(
)

# calculate or use given column widths
self.__column_widths = self.__auto_column_widths()
if options.column_widths:
# check that the right number of columns were specified
if len(options.column_widths) != self.__columns:
raise ValueError("Length of `column_widths` list must equal the number of columns")
# check that each column is at least as large as the minimum size
for i in range(len(options.column_widths)):
option = options.column_widths[i]
minimum = self.__column_widths[i]
if option is None:
option = minimum
elif option < minimum:
raise ValueError(
f"The value at index {i} of `column_widths` is {option} which is less than the minimum {minimum}."
)
self.__column_widths[i] = option
self.__column_widths = self.__calculate_column_widths(options.column_widths)

self.__alignments = options.alignments or [Alignment.CENTER] * self.__columns

Expand All @@ -78,9 +62,7 @@ def __init__(
raise ValueError("Cell padding must be greater than or equal to 0")

def __count_columns(self) -> int:
"""
Get the number of columns in the table based on the
provided header, footer, and body lists.
"""Get the number of columns in the table based on the provided header, footer, and body lists.

Returns:
The number of columns in the table
Expand All @@ -94,9 +76,8 @@ def __count_columns(self) -> int:
return 0

def __auto_column_widths(self) -> list[int]:
"""
Get the minimum number of characters needed for the values in
each column in the table with 1 space of padding on each side.
"""Get the minimum number of characters needed for the values in each column in the table
with 1 space of padding on each side.

Returns:
The minimum number of characters needed for each column
Expand All @@ -118,9 +99,35 @@ def widest_line(value: SupportsStr) -> int:
column_widths.append(max(header_size, body_size, footer_size) + self.__cell_padding * 2)
return column_widths

def __pad(self, cell_value: SupportsStr, width: int, alignment: Alignment) -> str:
def __calculate_column_widths(self, user_column_widths: list[int | None] | None) -> list[int]:
"""Calculate the width of each column in the table based on the cell values and provided column widths.

Args:
user_column_widths: The user specified column widths

Returns:
The width of each column in the table
"""
Pad a string of text to a given width with specified alignment
column_widths = self.__auto_column_widths()
if user_column_widths:
# check that the right number of columns were specified
if len(user_column_widths) != self.__columns:
raise ValueError("Length of `column_widths` list must equal the number of columns")
# check that each column is at least as large as the minimum size
for i in range(len(user_column_widths)):
option = user_column_widths[i]
minimum = column_widths[i]
if option is None:
option = minimum
elif option < minimum:
raise ValueError(
f"The value at index {i} of `column_widths` is {option} which is less than the minimum {minimum}."
)
column_widths[i] = option
return column_widths

def __pad(self, cell_value: SupportsStr, width: int, alignment: Alignment) -> str:
"""Pad a string of text to a given width with specified alignment

Args:
cell_value: The text in the cell to pad
Expand Down Expand Up @@ -154,8 +161,7 @@ def __row_to_ascii(
right_edge: str,
filler: str | list[SupportsStr],
) -> str:
"""
Assembles a line of text in the ascii table
"""Assembles a line of text in the ascii table

Returns:
The line in the ascii table
Expand All @@ -165,50 +171,96 @@ def __row_to_ascii(
num_lines = max(len(str(cell).splitlines()) for cell in filler) or 1
# repeat for each line of text in the cell
for line_index in range(num_lines):
# left edge of the row
output += left_edge
# add columns
for col_index in range(self.__columns):
# content between separators
col_content = ""
# if filler is a separator character, repeat it for the full width of the column
if isinstance(filler, str):
col_content = filler * self.__column_widths[col_index]
# otherwise, use the text from the corresponding column in the filler list
else:
# get the text of the current line in the cell
# if there are fewer lines in the current cell than others, empty string is used
col_lines = str(filler[col_index]).splitlines()
if line_index < len(col_lines):
col_content = col_lines[line_index]
# pad the text to the width of the column using the alignment
col_content = self.__pad(
col_content,
self.__column_widths[col_index],
self.__alignments[col_index],
)
output += col_content
# column separator
sep = column_separator
if col_index == 0 and self.__first_col_heading:
# use column heading if first column option is specified
sep = heading_col_sep
elif col_index == self.__columns - 2 and self.__last_col_heading:
# use column heading if last column option is specified
sep = heading_col_sep
elif col_index == self.__columns - 1:
# replace last separator with symbol for edge of the row
sep = right_edge
output += sep
output += "\n"
# don't use separation row if it's only space
if isinstance(filler, str) and output.strip() == "":
output = ""
output += self.__line_in_row_to_ascii(
line_index,
left_edge,
heading_col_sep,
column_separator,
right_edge,
filler,
)
# don't use separation row if it's only space
if isinstance(filler, str) and output.strip() == "":
output = ""
return output

def __top_edge_to_ascii(self) -> str:
def __line_in_row_to_ascii(
self,
line_index: int,
left_edge: str,
heading_col_sep: str,
column_separator: str,
right_edge: str,
filler: str | list[SupportsStr],
) -> str:
"""Assembles a line of text in the ascii table

Returns:
The line in the ascii table
"""
output = left_edge
# add columns
for col_index in range(self.__columns):
output += self.__line_in_cell_column_to_ascii(
line_index,
col_index,
heading_col_sep,
column_separator,
right_edge,
filler,
)
output += "\n"
return output

def __line_in_cell_column_to_ascii(
self,
line_index: int,
col_index: int,
heading_col_sep: str,
column_separator: str,
right_edge: str,
filler: str | list[SupportsStr],
) -> str:
"""Assembles a column of text in the ascii table

Returns:
The column in the ascii table
"""
Assembles the top edge of the ascii table
output = ""
# content between separators
col_content = ""
# if filler is a separator character, repeat it for the full width of the column
if isinstance(filler, str):
col_content = filler * self.__column_widths[col_index]
# otherwise, use the text from the corresponding column in the filler list
else:
# get the text of the current line in the cell
# if there are fewer lines in the current cell than others, empty string is used
col_lines = str(filler[col_index]).splitlines()
if line_index < len(col_lines):
col_content = col_lines[line_index]
# pad the text to the width of the column using the alignment
col_content = self.__pad(
col_content,
self.__column_widths[col_index],
self.__alignments[col_index],
)
output += col_content
# column separator
sep = column_separator
if col_index == 0 and self.__first_col_heading:
# use column heading if first column option is specified
sep = heading_col_sep
elif col_index == self.__columns - 2 and self.__last_col_heading:
# use column heading if last column option is specified
sep = heading_col_sep
elif col_index == self.__columns - 1:
# replace last separator with symbol for edge of the row
sep = right_edge
return output + sep

def __top_edge_to_ascii(self) -> str:
"""Assembles the top edge of the ascii table

Returns:
The top edge of the ascii table
Expand All @@ -222,8 +274,7 @@ def __top_edge_to_ascii(self) -> str:
)

def __bottom_edge_to_ascii(self) -> str:
"""
Assembles the bottom edge of the ascii table
"""Assembles the bottom edge of the ascii table

Returns:
The bottom edge of the ascii table
Expand All @@ -237,8 +288,7 @@ def __bottom_edge_to_ascii(self) -> str:
)

def __heading_row_to_ascii(self, row: list[SupportsStr]) -> str:
"""
Assembles the header or footer row line of the ascii table
"""Assembles the header or footer row line of the ascii table

Returns:
The header or footer row line of the ascii table
Expand All @@ -252,8 +302,7 @@ def __heading_row_to_ascii(self, row: list[SupportsStr]) -> str:
)

def __heading_sep_to_ascii(self) -> str:
"""
Assembles the separator below the header or above footer of the ascii table
"""Assembles the separator below the header or above footer of the ascii table

Returns:
The separator line
Expand All @@ -267,8 +316,7 @@ def __heading_sep_to_ascii(self) -> str:
)

def __body_to_ascii(self, body: list[list[SupportsStr]]) -> str:
"""
Assembles the body of the ascii table
"""Assembles the body of the ascii table

Returns:
The body of the ascii table
Expand All @@ -292,8 +340,7 @@ def __body_to_ascii(self, body: list[list[SupportsStr]]) -> str:
)

def to_ascii(self) -> str:
"""
Generates a formatted ASCII table
"""Generates a formatted ASCII table

Returns:
The generated ASCII table
Expand Down Expand Up @@ -329,8 +376,7 @@ def table2ascii(
cell_padding: int = 1,
style: TableStyle = PresetStyle.double_thin_compact,
) -> str:
"""
Convert a 2D Python table to ASCII text
"""Convert a 2D Python table to ASCII text

Args:
header: List of column values in the table's header row. All values should be :class:`str`
Expand Down