diff --git a/.github/workflows/lint.yml b/.github/workflows/lint.yml index 01ee7f7..97c81e4 100644 --- a/.github/workflows/lint.yml +++ b/.github/workflows/lint.yml @@ -16,10 +16,10 @@ jobs: - name: Checkout code uses: actions/checkout@v3 - - name: Set up python 3.7 + - name: Set up python 3.8 uses: actions/setup-python@v4 with: - python-version: 3.7 + python-version: 3.8 cache: pip cache-dependency-path: | setup.py diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 293d837..3828cce 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -6,13 +6,13 @@ ci: repos: - repo: https://github.com/psf/black - rev: 22.12.0 + rev: 23.1.0 hooks: - id: black name: Running black in all files. - repo: https://github.com/pycqa/isort - rev: 5.11.4 + rev: 5.12.0 hooks: - id: isort args: ["--profile", "black", "--extend-skip", "table2ascii"] 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/pyproject.toml b/pyproject.toml index 7b8a95a..fd814c1 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -5,7 +5,7 @@ build-backend = "setuptools.build_meta" [project] name = "table2ascii" -version = "1.1.0" +version = "1.1.1" authors = [{name = "Jonah Lawrence", email = "jonah@freshidea.com"}] description = "Convert 2D Python lists into Unicode/ASCII tables" readme = "README.md" @@ -54,8 +54,8 @@ docs = [ "sphinx-book-theme==0.3.3", ] dev = [ - "mypy>=0.982,<1", - "pre-commit>=2.0.0,<3", + "mypy>=0.982,<2", + "pre-commit>=2.0.0,<4", "pyright>=1.0.0,<2", "pytest>=6.0.0,<8", "slotscheck>=0.1.0,<1", diff --git a/setup.py b/setup.py index d32b777..b21e3f6 100644 --- a/setup.py +++ b/setup.py @@ -1,4 +1,7 @@ # /usr/bin/env python from setuptools import setup -setup() +setup( + packages=["table2ascii"], + package_data={"table2ascii": ["py.typed"]}, +) 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..b4b6314 100644 --- a/table2ascii/exceptions.py +++ b/table2ascii/exceptions.py @@ -40,8 +40,9 @@ 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 `\ [: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 +64,11 @@ 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 `\ [\ :class:`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 `\ [:class:`SupportsStr`]): + The first row with an invalid column count """ def __init__(self, body: Sequence[Sequence[SupportsStr]], expected_columns: int): @@ -90,8 +93,9 @@ 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 `\ [: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 +117,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 `\ [:data:`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 +153,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 +174,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 +213,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 `): The alignment value that caused the error """ def __init__(self, alignment: Any): @@ -230,8 +235,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 +261,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..dd092e2 100644 --- a/table2ascii/table_to_ascii.py +++ b/table2ascii/table_to_ascii.py @@ -677,23 +677,27 @@ 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 `\ [:class:`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 `\ [:class:`Sequence `\ [:class:`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 `\ [:class:`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`. 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 `\ [:class:`Sequence `\ [:data:`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`. 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`.