From b4feb720ed89bc11afa570794f9f45899c3c96ca Mon Sep 17 00:00:00 2001
From: Jonah Lawrence <jonah@freshidea.com>
Date: Thu, 29 Dec 2022 00:10:05 -0700
Subject: [PATCH 1/2] docs: Fix unlinked references

---
 docs/source/api.rst           | 33 +++++++++++++++++++------------
 table2ascii/__init__.py       | 30 ++++++++++++++++++++++++++++
 table2ascii/annotations.py    |  3 ++-
 table2ascii/exceptions.py     | 37 ++++++++++++++++++-----------------
 table2ascii/table_style.py    |  2 +-
 table2ascii/table_to_ascii.py |  3 ++-
 6 files changed, 74 insertions(+), 34 deletions(-)

diff --git a/docs/source/api.rst b/docs/source/api.rst
index 170e480..6cb1a29 100644
--- a/docs/source/api.rst
+++ b/docs/source/api.rst
@@ -39,31 +39,38 @@ TableStyle
 Exceptions
 ~~~~~~~~~~
 
-.. autoexception:: table2ascii.exceptions.Table2AsciiError
+.. autoexception:: Table2AsciiError
 
-.. autoexception:: table2ascii.exceptions.TableOptionError
+.. autoexception:: TableOptionError
 
-.. autoexception:: table2ascii.exceptions.ColumnCountMismatchError
+.. autoexception:: ColumnCountMismatchError
 
-.. autoexception:: table2ascii.exceptions.FooterColumnCountMismatchError
+.. autoexception:: FooterColumnCountMismatchError
 
-.. autoexception:: table2ascii.exceptions.BodyColumnCountMismatchError
+.. autoexception:: BodyColumnCountMismatchError
 
-.. autoexception:: table2ascii.exceptions.AlignmentCountMismatchError
+.. autoexception:: AlignmentCountMismatchError
 
-.. autoexception:: table2ascii.exceptions.InvalidCellPaddingError
+.. autoexception:: InvalidCellPaddingError
 
-.. autoexception:: table2ascii.exceptions.ColumnWidthsCountMismatchError
+.. autoexception:: ColumnWidthsCountMismatchError
 
-.. autoexception:: table2ascii.exceptions.ColumnWidthTooSmallError
+.. autoexception:: ColumnWidthTooSmallError
 
-.. autoexception:: table2ascii.exceptions.InvalidColumnWidthError
+.. autoexception:: InvalidColumnWidthError
 
-.. autoexception:: table2ascii.exceptions.InvalidAlignmentError
+.. autoexception:: InvalidAlignmentError
 
-.. autoexception:: table2ascii.exceptions.TableStyleTooLongError
+.. autoexception:: TableStyleTooLongError
 
 Warnings
 ~~~~~~~~
 
-.. autoclass:: table2ascii.exceptions.TableStyleTooShortWarning
+.. autoclass:: TableStyleTooShortWarning
+
+Annotations
+~~~~~~~~~~~
+
+.. autoclass:: SupportsStr
+    
+    .. automethod:: SupportsStr.__str__
diff --git a/table2ascii/__init__.py b/table2ascii/__init__.py
index a86dc02..bc53a37 100644
--- a/table2ascii/__init__.py
+++ b/table2ascii/__init__.py
@@ -5,6 +5,22 @@
 from typing import TYPE_CHECKING
 
 from .alignment import Alignment
+from .annotations import SupportsStr
+from .exceptions import (
+    AlignmentCountMismatchError,
+    BodyColumnCountMismatchError,
+    ColumnCountMismatchError,
+    ColumnWidthsCountMismatchError,
+    ColumnWidthTooSmallError,
+    FooterColumnCountMismatchError,
+    InvalidAlignmentError,
+    InvalidCellPaddingError,
+    InvalidColumnWidthError,
+    Table2AsciiError,
+    TableOptionError,
+    TableStyleTooLongError,
+    TableStyleTooShortWarning,
+)
 from .merge import Merge
 from .preset_style import PresetStyle
 from .table_style import TableStyle
@@ -23,4 +39,18 @@
     "PresetStyle",
     "TableStyle",
     "table2ascii",
+    "AlignmentCountMismatchError",
+    "BodyColumnCountMismatchError",
+    "ColumnCountMismatchError",
+    "ColumnWidthsCountMismatchError",
+    "ColumnWidthTooSmallError",
+    "FooterColumnCountMismatchError",
+    "InvalidAlignmentError",
+    "InvalidCellPaddingError",
+    "InvalidColumnWidthError",
+    "Table2AsciiError",
+    "TableOptionError",
+    "TableStyleTooLongError",
+    "TableStyleTooShortWarning",
+    "SupportsStr",
 ]
diff --git a/table2ascii/annotations.py b/table2ascii/annotations.py
index 60a4e3d..4434ced 100644
--- a/table2ascii/annotations.py
+++ b/table2ascii/annotations.py
@@ -10,8 +10,9 @@
 
 @runtime_checkable
 class SupportsStr(Protocol):
-    """An ABC with one abstract method __str__."""
+    """An abstract base class (ABC) with one abstract method :meth:`__str__`"""
 
     @abstractmethod
     def __str__(self) -> str:
+        """Return a string representation of the object"""
         pass
diff --git a/table2ascii/exceptions.py b/table2ascii/exceptions.py
index 0c57134..06f252d 100644
--- a/table2ascii/exceptions.py
+++ b/table2ascii/exceptions.py
@@ -40,8 +40,8 @@ class FooterColumnCountMismatchError(ColumnCountMismatchError):
     This class is a subclass of :class:`ColumnCountMismatchError`.
 
     Attributes:
-        footer (Sequence[SupportsStr]): The footer that caused the error
-        expected_columns (int): The number of columns that were expected
+        footer (:class:`Sequence <collections.abc.Sequence>`\ [:class:`SupportsStr`]): The footer that caused the error
+        expected_columns (:class:`int`): The number of columns that were expected
     """
 
     def __init__(self, footer: Sequence[SupportsStr], expected_columns: int):
@@ -63,9 +63,9 @@ class BodyColumnCountMismatchError(ColumnCountMismatchError):
     This class is a subclass of :class:`ColumnCountMismatchError`.
 
     Attributes:
-        body (Sequence[Sequence[SupportsStr]]): The body that caused the error
-        expected_columns (int): The number of columns that were expected
-        first_invalid_row (Sequence[SupportsStr]): The first row with an invalid column count
+        body (:class:`Sequence <collections.abc.Sequence>`\ [\ :class:`Sequence <collections.abc.Sequence>`\ [:class:`SupportsStr`]]): The body that caused the error
+        expected_columns (:class:`int`): The number of columns that were expected
+        first_invalid_row (:class:`Sequence <collections.abc.Sequence>`\ [:class:`SupportsStr`]): The first row with an invalid column count
     """
 
     def __init__(self, body: Sequence[Sequence[SupportsStr]], expected_columns: int):
@@ -90,8 +90,8 @@ class AlignmentCountMismatchError(ColumnCountMismatchError):
     This class is a subclass of :class:`ColumnCountMismatchError`.
 
     Attributes:
-        alignments (Sequence[Alignment]): The alignments that caused the error
-        expected_columns (int): The number of columns that were expected
+        alignments (:class:`Sequence <collections.abc.Sequence>`\ [:class:`Alignment`]): The alignments that caused the error
+        expected_columns (:class:`int`): The number of columns that were expected
     """
 
     def __init__(self, alignments: Sequence[Alignment], expected_columns: int):
@@ -113,8 +113,9 @@ class ColumnWidthsCountMismatchError(ColumnCountMismatchError):
     This class is a subclass of :class:`ColumnCountMismatchError`.
 
     Attributes:
-        column_widths (Sequence[Optional[int]]): The column widths that caused the error
-        expected_columns (int): The number of columns that were expected
+        column_widths (:class:`Sequence <collections.abc.Sequence>`\ [:data:`Optional <typing.Optional>`\ [:class:`int`]]):
+            The column widths that caused the error
+        expected_columns (:class:`int`): The number of columns that were expected
     """
 
     def __init__(self, column_widths: Sequence[int | None], expected_columns: int):
@@ -148,7 +149,7 @@ class InvalidCellPaddingError(TableOptionError):
     This class is a subclass of :class:`TableOptionError`.
 
     Attributes:
-        padding (int): The padding that caused the error
+        padding (:class:`int`): The padding that caused the error
     """
 
     def __init__(self, padding: int):
@@ -169,9 +170,9 @@ class ColumnWidthTooSmallError(TableOptionError):
     This class is a subclass of :class:`TableOptionError`.
 
     Attributes:
-        column_index (int): The index of the column that caused the error
-        column_width (int): The column width that caused the error
-        min_width (int): The minimum width that is allowed
+        column_index (:class:`int`): The index of the column that caused the error
+        column_width (:class:`int`): The column width that caused the error
+        min_width (:class:`int`): The minimum width that is allowed
     """
 
     def __init__(self, column_index: int, column_width: int, min_width: int | None = None):
@@ -208,7 +209,7 @@ class InvalidAlignmentError(TableOptionError):
     This class is a subclass of :class:`TableOptionError`.
 
     Attributes:
-        alignment (Any): The alignment value that caused the error
+        alignment (:data:`Any <typing.Any>`): The alignment value that caused the error
     """
 
     def __init__(self, alignment: Any):
@@ -230,8 +231,8 @@ class TableStyleTooLongError(Table2AsciiError, ValueError):
     This class is a subclass of :class:`Table2AsciiError` and :class:`ValueError`.
 
     Attributes:
-        string (str): The string that caused the error
-        max_characters (int): The maximum number of characters that are allowed
+        string (:class:`str`): The string that caused the error
+        max_characters (:class:`int`): The maximum number of characters that are allowed
     """
 
     def __init__(self, string: str, max_characters: int):
@@ -256,8 +257,8 @@ class TableStyleTooShortWarning(UserWarning):
     It can be silenced using :func:`warnings.filterwarnings`.
 
     Attributes:
-        string (str): The string that caused the warning
-        max_characters (int): The number of characters that :class:`TableStyle` accepts
+        string (:class:`str`): The string that caused the warning
+        max_characters (:class:`int`): The number of characters that :class:`TableStyle` accepts
     """
 
     def __init__(self, string: str, max_characters: int):
diff --git a/table2ascii/table_style.py b/table2ascii/table_style.py
index 8ecc12e..23db0ac 100644
--- a/table2ascii/table_style.py
+++ b/table2ascii/table_style.py
@@ -145,7 +145,7 @@ def set(self, **kwargs: str) -> "TableStyle":
 
         Example::
 
-            TableStyle().set(top_left_corner="╔", top_and_bottom_edge="═")
+            TableStyle.from_string("~" * 30).set(left_and_right_edge="", col_sep="")
         """
         for key, value in kwargs.items():
             setattr(self, key, value)
diff --git a/table2ascii/table_to_ascii.py b/table2ascii/table_to_ascii.py
index c4359a8..2d7c8e6 100644
--- a/table2ascii/table_to_ascii.py
+++ b/table2ascii/table_to_ascii.py
@@ -687,7 +687,8 @@ def table2ascii(
             Defaults to :py:obj:`False`.
         last_col_heading: Whether to add a header column separator before the last column.
             Defaults to :py:obj:`False`.
-        column_widths: List of widths in characters for each column. Any value of :py:obj:`None`
+        column_widths (:data:`Optional <typing.Optional>`\ [:class:`Sequence <collections.abc.Sequence>`\ [:data:`Optional <typing.Optional>`\ [:class:`int`]]]):
+            List of widths in characters for each column. Any value of :py:obj:`None`
             indicates that the column width should be determined automatically. If :py:obj:`None`
             is passed instead of a :class:`~collections.abc.Sequence`, all columns will be automatically
             sized. Defaults to :py:obj:`None`.

From 4b60c41a363fd069d155e9e26be0fe7709696908 Mon Sep 17 00:00:00 2001
From: Jonah Lawrence <jonah@freshidea.com>
Date: Thu, 29 Dec 2022 00:23:07 -0700
Subject: [PATCH 2/2] table2ascii fixes

---
 table2ascii/exceptions.py     | 12 ++++++++----
 table2ascii/table_to_ascii.py | 13 ++++++++-----
 2 files changed, 16 insertions(+), 9 deletions(-)

diff --git a/table2ascii/exceptions.py b/table2ascii/exceptions.py
index 06f252d..b4b6314 100644
--- a/table2ascii/exceptions.py
+++ b/table2ascii/exceptions.py
@@ -40,7 +40,8 @@ class FooterColumnCountMismatchError(ColumnCountMismatchError):
     This class is a subclass of :class:`ColumnCountMismatchError`.
 
     Attributes:
-        footer (:class:`Sequence <collections.abc.Sequence>`\ [:class:`SupportsStr`]): The footer that caused the error
+        footer (:class:`Sequence <collections.abc.Sequence>`\ [:class:`SupportsStr`]):
+            The footer that caused the error
         expected_columns (:class:`int`): The number of columns that were expected
     """
 
@@ -63,9 +64,11 @@ class BodyColumnCountMismatchError(ColumnCountMismatchError):
     This class is a subclass of :class:`ColumnCountMismatchError`.
 
     Attributes:
-        body (:class:`Sequence <collections.abc.Sequence>`\ [\ :class:`Sequence <collections.abc.Sequence>`\ [:class:`SupportsStr`]]): The body that caused the error
+        body (:class:`Sequence <collections.abc.Sequence>`\ [\ :class:`Sequence <collections.abc.Sequence>`\ [:class:`SupportsStr`]]):
+            The body that caused the error
         expected_columns (:class:`int`): The number of columns that were expected
-        first_invalid_row (:class:`Sequence <collections.abc.Sequence>`\ [:class:`SupportsStr`]): The first row with an invalid column count
+        first_invalid_row (:class:`Sequence <collections.abc.Sequence>`\ [:class:`SupportsStr`]):
+            The first row with an invalid column count
     """
 
     def __init__(self, body: Sequence[Sequence[SupportsStr]], expected_columns: int):
@@ -90,7 +93,8 @@ class AlignmentCountMismatchError(ColumnCountMismatchError):
     This class is a subclass of :class:`ColumnCountMismatchError`.
 
     Attributes:
-        alignments (:class:`Sequence <collections.abc.Sequence>`\ [:class:`Alignment`]): The alignments that caused the error
+        alignments (:class:`Sequence <collections.abc.Sequence>`\ [:class:`Alignment`]):
+            The alignments that caused the error
         expected_columns (:class:`int`): The number of columns that were expected
     """
 
diff --git a/table2ascii/table_to_ascii.py b/table2ascii/table_to_ascii.py
index 2d7c8e6..dd092e2 100644
--- a/table2ascii/table_to_ascii.py
+++ b/table2ascii/table_to_ascii.py
@@ -677,11 +677,14 @@ def table2ascii(
     """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`
+        header (:data:`Optional <typing.Optional>`\ [:class:`Sequence <collections.abc.Sequence>`\ [:class:`SupportsStr`]]):
+            List of column values in the table's header row. All values should be :class:`str`
             or support :class:`str` conversion. If not specified, the table will not have a header row.
-        body: 2-dimensional list of values in the table's body. All values should be :class:`str`
+        body (:data:`Optional <typing.Optional>`\ [:class:`Sequence <collections.abc.Sequence>`\ [:class:`Sequence <collections.abc.Sequence>`\ [:class:`SupportsStr`]]]):
+            2-dimensional list of values in the table's body. All values should be :class:`str`
             or support :class:`str` conversion. If not specified, the table will not have a body.
-        footer: List of column values in the table's footer row. All values should be :class:`str`
+        footer (:data:`Optional <typing.Optional>`\ [:class:`Sequence <collections.abc.Sequence>`\ [:class:`SupportsStr`]]):
+            List of column values in the table's footer row. All values should be :class:`str`
             or support :class:`str` conversion. If not specified, the table will not have a footer row.
         first_col_heading: Whether to add a header column separator after the first column.
             Defaults to :py:obj:`False`.
@@ -693,8 +696,8 @@ def table2ascii(
             is passed instead of a :class:`~collections.abc.Sequence`, all columns will be automatically
             sized. Defaults to :py:obj:`None`.
         alignments: List of alignments for each column
-            (ex. ``[Alignment.LEFT, Alignment.CENTER, Alignment.RIGHT, Alignment.DECIMAL]``)
-            or a single alignment to apply to all columns (ex. ``Alignment.LEFT``).
+            (ex. [:attr:`Alignment.LEFT`, :attr:`Alignment.CENTER`, :attr:`Alignment.RIGHT`, :attr:`Alignment.DECIMAL`])
+            or a single alignment to apply to all columns (ex. :attr:`Alignment.LEFT`).
             If not specified or set to :py:obj:`None`, all columns will be center-aligned.
             Defaults to :py:obj:`None`.