From fc473a1cf8d91cbb4df8865a756ba664c6542682 Mon Sep 17 00:00:00 2001 From: Marc Mueller <30130371+cdce8p@users.noreply.github.com> Date: Wed, 16 Oct 2024 15:52:00 +0200 Subject: [PATCH] Add IntEnum for HRuleStyle and VRuleStyle (#327) --- src/prettytable/__init__.py | 4 + src/prettytable/prettytable.py | 173 ++++++++++++++++++++------------- tests/test_prettytable.py | 12 +-- 3 files changed, 113 insertions(+), 76 deletions(-) diff --git a/src/prettytable/__init__.py b/src/prettytable/__init__.py index 0ee4cf7..26ffd4b 100644 --- a/src/prettytable/__init__.py +++ b/src/prettytable/__init__.py @@ -14,9 +14,11 @@ PLAIN_COLUMNS, RANDOM, SINGLE_BORDER, + HRuleStyle, PrettyTable, TableHandler, TableStyle, + VRuleStyle, from_csv, from_db_cursor, from_html, @@ -37,9 +39,11 @@ "ORGMODE", "PLAIN_COLUMNS", "RANDOM", + "HRuleStyle", "PrettyTable", "TableHandler", "TableStyle", + "VRuleStyle", "from_csv", "from_db_cursor", "from_html", diff --git a/src/prettytable/prettytable.py b/src/prettytable/prettytable.py index 96ff159..4fb9d7c 100644 --- a/src/prettytable/prettytable.py +++ b/src/prettytable/prettytable.py @@ -46,11 +46,18 @@ from _typeshed import SupportsRichComparison from typing_extensions import Self, TypeAlias -# hrule styles -FRAME = 0 -ALL = 1 -NONE = 2 -HEADER = 3 + +class HRuleStyle(IntEnum): + FRAME = 0 + ALL = 1 + NONE = 2 + HEADER = 3 + + +class VRuleStyle(IntEnum): + FRAME = 0 + ALL = 1 + NONE = 2 class TableStyle(IntEnum): @@ -65,6 +72,10 @@ class TableStyle(IntEnum): # keep for backwards compatibility +FRAME: Final = 0 +ALL: Final = 1 +NONE: Final = 2 +HEADER: Final = 3 DEFAULT: Final = TableStyle.DEFAULT MSWORD_FRIENDLY: Final = TableStyle.MSWORD_FRIENDLY PLAIN_COLUMNS: Final = TableStyle.PLAIN_COLUMNS @@ -111,6 +122,8 @@ class PrettyTable: _header_style: HeaderStyleType _border: bool _preserve_internal_border: bool + _hrules: HRuleStyle + _vrules: VRuleStyle _padding_width: int _left_padding_width: int | None _right_padding_width: int | None @@ -155,9 +168,9 @@ def __init__(self, field_names: Sequence[str] | None = None, **kwargs) -> None: preserve_internal_border - print a border inside the table even if border is disabled (True or False) hrules - controls printing of horizontal rules after rows. - Allowed values: FRAME, HEADER, ALL, NONE + Allowed values: HRuleStyle vrules - controls printing of vertical rules between columns. - Allowed values: FRAME, ALL, NONE + Allowed values: VRuleStyle int_format - controls formatting of integer data float_format - controls formatting of floating point data custom_format - controls formatting of any column using callable @@ -286,8 +299,8 @@ def __init__(self, field_names: Sequence[str] | None = None, **kwargs) -> None: self._preserve_internal_border = kwargs["preserve_internal_border"] else: self._preserve_internal_border = False - self._hrules = kwargs["hrules"] or FRAME - self._vrules = kwargs["vrules"] or ALL + self._hrules = kwargs["hrules"] or HRuleStyle.FRAME + self._vrules = kwargs["vrules"] or VRuleStyle.ALL self._sortby = kwargs["sortby"] or None if kwargs["reversesort"] in (True, False): @@ -598,16 +611,16 @@ def _validate_function(self, name, val): def _validate_hrules(self, name, val): try: - assert val in (ALL, FRAME, HEADER, NONE) + assert val in list(HRuleStyle) except AssertionError: - msg = f"Invalid value for {name}. Must be ALL, FRAME, HEADER or NONE." + msg = f"Invalid value for {name}. Must be HRuleStyle." raise ValueError(msg) def _validate_vrules(self, name, val): try: - assert val in (ALL, FRAME, NONE) + assert val in list(VRuleStyle) except AssertionError: - msg = f"Invalid value for {name}. Must be ALL, FRAME, or NONE." + msg = f"Invalid value for {name}. Must be VRuleStyle." raise ValueError(msg) def _validate_field_name(self, name, val): @@ -963,30 +976,30 @@ def preserve_internal_border(self, val: bool) -> None: self._preserve_internal_border = val @property - def hrules(self): + def hrules(self) -> HRuleStyle: """Controls printing of horizontal rules after rows Arguments: - hrules - horizontal rules style. Allowed values: FRAME, ALL, HEADER, NONE""" + hrules - horizontal rules style. Allowed values: HRuleStyle""" return self._hrules @hrules.setter - def hrules(self, val) -> None: + def hrules(self, val: HRuleStyle) -> None: self._validate_option("hrules", val) self._hrules = val @property - def vrules(self): + def vrules(self) -> VRuleStyle: """Controls printing of vertical rules between columns Arguments: - vrules - vertical rules style. Allowed values: FRAME, ALL, NONE""" + vrules - vertical rules style. Allowed values: VRuleStyle""" return self._vrules @vrules.setter - def vrules(self, val) -> None: + def vrules(self, val: VRuleStyle) -> None: self._validate_option("vrules", val) self._vrules = val @@ -1401,7 +1414,7 @@ def _set_orgmode_style(self) -> None: def _set_markdown_style(self) -> None: self.header = True self.border = True - self._hrules = None + self._hrules = HRuleStyle.HEADER self.padding_width = 1 self.left_padding_width = 1 self.right_padding_width = 1 @@ -1412,8 +1425,8 @@ def _set_markdown_style(self) -> None: def _set_default_style(self) -> None: self.header = True self.border = True - self._hrules = FRAME - self._vrules = ALL + self._hrules = HRuleStyle.FRAME + self._vrules = VRuleStyle.ALL self.padding_width = 1 self.left_padding_width = 1 self.right_padding_width = 1 @@ -1433,7 +1446,7 @@ def _set_default_style(self) -> None: def _set_msword_style(self) -> None: self.header = True self.border = True - self._hrules = NONE + self._hrules = HRuleStyle.NONE self.padding_width = 1 self.left_padding_width = 1 self.right_padding_width = 1 @@ -1478,8 +1491,8 @@ def _set_random_style(self) -> None: self.header = random.choice((True, False)) self.border = random.choice((True, False)) - self._hrules = random.choice((ALL, FRAME, HEADER, NONE)) - self._vrules = random.choice((ALL, FRAME, NONE)) + self._hrules = random.choice(list(HRuleStyle)) + self._vrules = random.choice(list(VRuleStyle)) self.left_padding_width = random.randint(0, 5) self.right_padding_width = random.randint(0, 5) self.vertical_char = random.choice(r"~!@#$%^&*()_+|-=\{}[];':\",./;<>?") @@ -1666,9 +1679,9 @@ def _format_value(self, field: str, value: Any) -> str: return formatter(field, value) def _compute_table_width(self, options) -> int: - if options["vrules"] == FRAME: + if options["vrules"] == VRuleStyle.FRAME: table_width = 2 - if options["vrules"] == ALL: + if options["vrules"] == VRuleStyle.ALL: table_width = 1 else: table_width = 0 @@ -1730,7 +1743,7 @@ def _compute_widths(self, rows: list[list[str]], options) -> None: if self._min_table_width or options["title"]: if options["title"]: title_width = len(options["title"]) + per_col_padding - if options["vrules"] in (FRAME, ALL): + if options["vrules"] in (VRuleStyle.FRAME, VRuleStyle.ALL): title_width += 2 else: title_width = 0 @@ -1842,9 +1855,9 @@ def get_string(self, **kwargs) -> str: preserve_internal_border - print a border inside the table even if border is disabled (True or False) hrules - controls printing of horizontal rules after rows. - Allowed values: ALL, FRAME, HEADER, NONE + Allowed values: HRuleStyle vrules - controls printing of vertical rules between columns. - Allowed values: FRAME, ALL, NONE + Allowed values: VRuleStyle int_format - controls formatting of integer data float_format - controls formatting of floating point data custom_format - controls formatting of any column using callable @@ -1904,9 +1917,12 @@ def get_string(self, **kwargs) -> str: # Add header or top of border if options["header"]: lines.append(self._stringify_header(options)) - elif options["border"] and options["hrules"] in (ALL, FRAME): + elif options["border"] and options["hrules"] in ( + HRuleStyle.ALL, + HRuleStyle.FRAME, + ): lines.append(self._stringify_hrule(options, where="top_")) - if title and options["vrules"] in (ALL, FRAME): + if title and options["vrules"] in (VRuleStyle.ALL, VRuleStyle.FRAME): lines[-1] = ( self.left_junction_char + lines[-1][1:-1] + self.right_junction_char ) @@ -1926,7 +1942,7 @@ def get_string(self, **kwargs) -> str: ) # Add bottom of border - if options["border"] and options["hrules"] == FRAME: + if options["border"] and options["hrules"] == HRuleStyle.FRAME: lines.append(self._stringify_hrule(options, where="bottom_")) if "orgmode" in self.__dict__ and self.orgmode: @@ -1944,7 +1960,7 @@ def _stringify_hrule( if not options["border"] and not options["preserve_internal_border"]: return "" lpad, rpad = self._get_padding_widths(options) - if options["vrules"] in (ALL, FRAME): + if options["vrules"] in (VRuleStyle.ALL, VRuleStyle.FRAME): bits = [options[where + "left_junction_char"]] else: bits = [options["horizontal_char"]] @@ -1966,11 +1982,11 @@ def _stringify_hrule( line = line[:-2] + self._horizontal_align_char + " " bits.append(line) - if options["vrules"] == ALL: + if options["vrules"] == VRuleStyle.ALL: bits.append(options[where + "junction_char"]) else: bits.append(options["horizontal_char"]) - if options["vrules"] in (ALL, FRAME): + if options["vrules"] in (VRuleStyle.ALL, VRuleStyle.FRAME): bits.pop() bits.append(options[where + "right_junction_char"]) @@ -1983,16 +1999,17 @@ def _stringify_title(self, title: str, options) -> str: lines: list[str] = [] lpad, rpad = self._get_padding_widths(options) if options["border"]: - if options["vrules"] == ALL: - options["vrules"] = FRAME + if options["vrules"] == VRuleStyle.ALL: + options["vrules"] = VRuleStyle.FRAME lines.append(self._stringify_hrule(options, "top_")) - options["vrules"] = ALL - elif options["vrules"] == FRAME: + options["vrules"] = VRuleStyle.ALL + elif options["vrules"] == VRuleStyle.FRAME: lines.append(self._stringify_hrule(options, "top_")) bits: list[str] = [] endpoint = ( options["vertical_char"] - if options["vrules"] in (ALL, FRAME) and options["border"] + if options["vrules"] in (VRuleStyle.ALL, VRuleStyle.FRAME) + and options["border"] else " " ) bits.append(endpoint) @@ -2009,9 +2026,12 @@ def _stringify_header(self, options) -> str: bits: list[str] = [] lpad, rpad = self._get_padding_widths(options) if options["border"]: - if options["hrules"] in (ALL, FRAME): + if options["hrules"] in (HRuleStyle.ALL, HRuleStyle.FRAME): bits.append(self._stringify_hrule(options, "top_")) - if options["title"] and options["vrules"] in (ALL, FRAME): + if options["title"] and options["vrules"] in ( + VRuleStyle.ALL, + VRuleStyle.FRAME, + ): left_j_len = len(self.left_junction_char) right_j_len = len(self.right_junction_char) bits[-1] = ( @@ -2020,13 +2040,13 @@ def _stringify_header(self, options) -> str: + self.right_junction_char ) bits.append("\n") - if options["vrules"] in (ALL, FRAME): + if options["vrules"] in (VRuleStyle.ALL, VRuleStyle.FRAME): bits.append(options["vertical_char"]) else: bits.append(" ") # For tables with no data or field names if not self._field_names: - if options["vrules"] in (ALL, FRAME): + if options["vrules"] in (VRuleStyle.ALL, VRuleStyle.FRAME): bits.append(options["vertical_char"]) else: bits.append(" ") @@ -2051,7 +2071,7 @@ def _stringify_header(self, options) -> str: + " " * rpad ) if options["border"] or options["preserve_internal_border"]: - if options["vrules"] == ALL: + if options["vrules"] == VRuleStyle.ALL: bits.append(options["vertical_char"]) else: bits.append(" ") @@ -2063,12 +2083,12 @@ def _stringify_header(self, options) -> str: bits.append(" ") # If vrules is FRAME, then we just appended a space at the end # of the last field, when we really want a vertical character - if options["border"] and options["vrules"] == FRAME: + if options["border"] and options["vrules"] == VRuleStyle.FRAME: bits.pop() bits.append(options["vertical_char"]) if (options["border"] or options["preserve_internal_border"]) and options[ "hrules" - ] != NONE: + ] != HRuleStyle.NONE: bits.append("\n") bits.append(self._hrule) return "".join(bits) @@ -2106,7 +2126,7 @@ def _stringify_row(self, row: list[str], options, hrule: str) -> str: for y in range(0, row_height): bits.append([]) if options["border"]: - if options["vrules"] in (ALL, FRAME): + if options["vrules"] in (VRuleStyle.ALL, VRuleStyle.FRAME): bits[y].append(self.vertical_char) else: bits[y].append(" ") @@ -2137,7 +2157,7 @@ def _stringify_row(self, row: list[str], options, hrule: str) -> str: + " " * rpad ) if options["border"] or options["preserve_internal_border"]: - if options["vrules"] == ALL: + if options["vrules"] == VRuleStyle.ALL: bits[y].append(self.vertical_char) else: bits[y].append(" ") @@ -2151,11 +2171,11 @@ def _stringify_row(self, row: list[str], options, hrule: str) -> str: # If vrules is FRAME, then we just appended a space at the end # of the last field, when we really want a vertical character for y in range(0, row_height): - if options["border"] and options["vrules"] == FRAME: + if options["border"] and options["vrules"] == VRuleStyle.FRAME: bits[y].pop() bits[y].append(options["vertical_char"]) - if options["border"] and options["hrules"] == ALL: + if options["border"] and options["hrules"] == HRuleStyle.ALL: bits[row_height - 1].append("\n") bits[row_height - 1].append(hrule) @@ -2280,9 +2300,9 @@ def get_html_string(self, **kwargs) -> str: preserve_internal_border - print a border inside the table even if border is disabled (True or False) hrules - controls printing of horizontal rules after rows. - Allowed values: ALL, FRAME, HEADER, NONE + Allowed values: HRuleStyle vrules - controls printing of vertical rules between columns. - Allowed values: FRAME, ALL, NONE + Allowed values: VRuleStyle int_format - controls formatting of integer data float_format - controls formatting of floating point data custom_format - controls formatting of any column using callable @@ -2379,19 +2399,28 @@ def _get_formatted_html_string(self, options) -> str: open_tag = [" str: preserve_internal_border - print a border inside the table even if border is disabled (True or False) hrules - controls printing of horizontal rules after rows. - Allowed values: ALL, FRAME, HEADER, NONE + Allowed values: HRuleStyle vrules - controls printing of vertical rules between columns. - Allowed values: FRAME, ALL, NONE + Allowed values: VRuleStyle int_format - controls formatting of integer data float_format - controls formatting of floating point data sortby - name of field to sort rows by @@ -2543,19 +2572,25 @@ def _get_formatted_latex_string(self, options) -> str: wanted_fields = self._field_names wanted_alignments = [self._align[field] for field in wanted_fields] - if options["border"] and options["vrules"] == ALL: + if options["border"] and options["vrules"] == VRuleStyle.ALL: alignment_str = "|".join(wanted_alignments) elif not options["border"] and options["preserve_internal_border"]: alignment_str = "|".join(wanted_alignments) else: alignment_str = "".join(wanted_alignments) - if options["border"] and options["vrules"] in [ALL, FRAME]: + if options["border"] and options["vrules"] in [ + VRuleStyle.ALL, + VRuleStyle.FRAME, + ]: alignment_str = "|" + alignment_str + "|" begin_cmd = f"\\begin{{tabular}}{{{alignment_str}}}" lines.append(begin_cmd) - if options["border"] and options["hrules"] in [ALL, FRAME]: + if options["border"] and options["hrules"] in [ + HRuleStyle.ALL, + HRuleStyle.FRAME, + ]: lines.append("\\hline") # Headers @@ -2563,7 +2598,7 @@ def _get_formatted_latex_string(self, options) -> str: lines.append(" & ".join(wanted_fields) + " \\\\") if (options["border"] or options["preserve_internal_border"]) and options[ "hrules" - ] in [ALL, HEADER]: + ] in [HRuleStyle.ALL, HRuleStyle.HEADER]: lines.append("\\hline") # Data @@ -2575,10 +2610,10 @@ def _get_formatted_latex_string(self, options) -> str: d for f, d in zip(self._field_names, row) if f in wanted_fields ] lines.append(" & ".join(wanted_data) + " \\\\") - if options["border"] and options["hrules"] == ALL: + if options["border"] and options["hrules"] == HRuleStyle.ALL: lines.append("\\hline") - if options["border"] and options["hrules"] == FRAME: + if options["border"] and options["hrules"] == HRuleStyle.FRAME: lines.append("\\hline") lines.append("\\end{tabular}") diff --git a/tests/test_prettytable.py b/tests/test_prettytable.py index de4f65b..0dcd591 100644 --- a/tests/test_prettytable.py +++ b/tests/test_prettytable.py @@ -1666,13 +1666,11 @@ class TestStyle: pytest.param( RANDOM, """ -'^^^^^'^^^^^^^^^^^'^^^^^^^^^^'^^^^^^^^^^' -% 1% value 1% value2% value3% -'^^^^^'^^^^^^^^^^^'^^^^^^^^^^'^^^^^^^^^^' -% 4% value 4% value5% value6% -'^^^^^'^^^^^^^^^^^'^^^^^^^^^^'^^^^^^^^^^' -% 7% value 7% value8% value9% -'^^^^^'^^^^^^^^^^^'^^^^^^^^^^'^^^^^^^^^^' +'^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^' +% 1 value 1 value2 value3% +% 4 value 4 value5 value6% +% 7 value 7 value8 value9% +'^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^' """, id="RANDOM", ),