diff --git a/README.md b/README.md
index de9e288..ca0e1c6 100644
--- a/README.md
+++ b/README.md
@@ -123,7 +123,7 @@ output = table2ascii(
body=[["10", "30", "40", "35"], ["20", "10", "20", "5"]],
style=PresetStyle.plain,
cell_padding=0,
- alignments=[Alignment.LEFT] * 4,
+ alignments=Alignment.LEFT,
)
print(output)
@@ -203,18 +203,18 @@ All parameters are optional. At least one of `header`, `body`, and `footer` must
Refer to the [documentation](https://table2ascii.readthedocs.io/en/stable/api.html#table2ascii) for more information.
-| Option | Type | Default | Description |
-| :-----------------: | :----------------------------: | :-------------------: | :--------------------------------------------------------------------------------------------------: |
-| `header` | `Sequence[SupportsStr]` | `None` | First table row seperated by header row separator. Values should support `str()` |
-| `body` | `Sequence[Sequence[Sequence]]` | `None` | 2D List of rows for the main section of the table. Values should support `str()` |
-| `footer` | `Sequence[Sequence]` | `None` | Last table row seperated by header row separator. Values should support `str()` |
-| `column_widths` | `Sequence[Optional[int]]` | `None` (automatic) | List of column widths in characters for each column |
-| `alignments` | `Sequence[Alignment]` | `None` (all centered) | Column alignments
(ex. `[Alignment.LEFT, Alignment.CENTER, Alignment.RIGHT, Alignment.DECIMAL]`) |
-| `style` | `TableStyle` | `double_thin_compact` | Table style to use for the table\* |
-| `first_col_heading` | `bool` | `False` | Whether to add a heading column separator after the first column |
-| `last_col_heading` | `bool` | `False` | Whether to add a heading column separator before the last column |
-| `cell_padding` | `int` | `1` | The minimum number of spaces to add between the cell content and the cell border |
-| `use_wcwidth` | `bool` | `True` | Whether to use [wcwidth][wcwidth] instead of `len()` to calculate cell width |
+| Option | Supported Types | Description |
+| :-----------------: | :-----------------------------------------------------------------------------: | :--------------------------------------------------------------------------------------------------: |
+| `header` | `Sequence[SupportsStr]`, `None`
(Default: `None`) | First table row seperated by header row separator. Values should support `str()` |
+| `body` | `Sequence[Sequence[SupportsStr]]`, `None`
(Default: `None`) | 2D List of rows for the main section of the table. Values should support `str()` |
+| `footer` | `Sequence[SupportsStr]`, `None`
(Default: `None`) | Last table row seperated by header row separator. Values should support `str()` |
+| `column_widths` | `Sequence[Optional[int]]`, `None`
(Default: `None` / automatic) | List of column widths in characters for each column |
+| `alignments` | `Sequence[Alignment]`, `Alignment`, `None`
(Default: `None` / all centered) | Column alignments
(ex. `[Alignment.LEFT, Alignment.CENTER, Alignment.RIGHT, Alignment.DECIMAL]`) |
+| `style` | `TableStyle`
(Default: `double_thin_compact`) | Table style to use for the table\* |
+| `first_col_heading` | `bool`
(Default: `False`) | Whether to add a heading column separator after the first column |
+| `last_col_heading` | `bool`
(Default: `False`) | Whether to add a heading column separator before the last column |
+| `cell_padding` | `int`
(Default: `1`) | The minimum number of spaces to add between the cell content and the cell border |
+| `use_wcwidth` | `bool`
(Default: `True`) | Whether to use [wcwidth][wcwidth] instead of `len()` to calculate cell width |
[wcwidth]: https://pypi.org/project/wcwidth/
diff --git a/docs/source/usage.rst b/docs/source/usage.rst
index 823c23e..d1eb820 100644
--- a/docs/source/usage.rst
+++ b/docs/source/usage.rst
@@ -109,7 +109,7 @@ Use a preset style
body=[["10", "30", "40", "35"], ["20", "10", "20", "5"]],
style=PresetStyle.plain,
cell_padding=0,
- alignments=[Alignment.LEFT] * 4,
+ alignments=Alignment.LEFT,
)
print(output)
diff --git a/table2ascii/alignment.py b/table2ascii/alignment.py
index 2ae487f..041d167 100644
--- a/table2ascii/alignment.py
+++ b/table2ascii/alignment.py
@@ -4,7 +4,7 @@
class Alignment(IntEnum):
"""Enum for text alignment types within a table cell
- Example::
+ A list of alignment types can be used to align each column individually::
from table2ascii import Alignment, table2ascii
@@ -15,6 +15,8 @@ class Alignment(IntEnum):
["Cheese", "Dairy", "$10.99", "8.2"],
["Apples", "Produce", "$0.99", "10.00"],
],
+ # Align the first column to the left, the second to the center,
+ # the third to the right, and the fourth to the decimal point
alignments=[Alignment.LEFT, Alignment.CENTER, Alignment.RIGHT, Alignment.DECIMAL],
)
@@ -28,6 +30,27 @@ class Alignment(IntEnum):
╚════════════════════════════════════════╝
\"\"\"
+ A single alignment type can be used for all columns::
+
+ table2ascii(
+ header=["First Name", "Last Name", "Age"],
+ body=[
+ ["John", "Smith", 30],
+ ["Jane", "Doe", 28],
+ ],
+ # Align all columns to the left
+ alignments=Alignment.LEFT,
+ )
+
+ \"\"\"
+ ╔══════════════════════════════╗
+ ║ First Name Last Name Age ║
+ ╟──────────────────────────────╢
+ ║ John Smith 30 ║
+ ║ Jane Doe 28 ║
+ ╚══════════════════════════════╝
+ \"\"\"
+
.. note::
If the :attr:`DECIMAL` alignment type is used, any cell values that are
diff --git a/table2ascii/options.py b/table2ascii/options.py
index 36f6ee0..e88bd44 100644
--- a/table2ascii/options.py
+++ b/table2ascii/options.py
@@ -19,7 +19,7 @@ class Options:
first_col_heading: bool
last_col_heading: bool
column_widths: Sequence[int | None] | None
- alignments: Sequence[Alignment] | None
+ alignments: Sequence[Alignment] | Alignment | None
cell_padding: int
style: TableStyle
use_wcwidth: bool
diff --git a/table2ascii/table_to_ascii.py b/table2ascii/table_to_ascii.py
index 0510bd1..46603d7 100644
--- a/table2ascii/table_to_ascii.py
+++ b/table2ascii/table_to_ascii.py
@@ -67,11 +67,16 @@ def __init__(
if not header and not body and not footer:
raise NoHeaderBodyOrFooterError()
- self.__alignments = options.alignments or [Alignment.CENTER] * self.__columns
+ alignments = options.alignments if options.alignments is not None else Alignment.CENTER
+
+ # if alignments is a single Alignment, convert it to a list of that Alignment
+ self.__alignments: list[Alignment] = (
+ [alignments] * self.__columns if isinstance(alignments, Alignment) else list(alignments)
+ )
# check if alignments specified have a different number of columns
- if options.alignments and len(options.alignments) != self.__columns:
- raise AlignmentCountMismatchError(options.alignments, self.__columns)
+ if len(self.__alignments) != self.__columns:
+ raise AlignmentCountMismatchError(self.__alignments, self.__columns)
# keep track of the number widths and positions of the decimal points for decimal alignment
decimal_widths, decimal_positions = self.__calculate_decimal_widths_and_positions()
@@ -634,16 +639,13 @@ def table2ascii(
first_col_heading: bool = False,
last_col_heading: bool = False,
column_widths: Sequence[int | None] | None = None,
- alignments: Sequence[Alignment] | None = None,
+ alignments: Sequence[Alignment] | Alignment | None = None,
cell_padding: int = 1,
style: TableStyle = PresetStyle.double_thin_compact,
use_wcwidth: bool = True,
) -> str:
"""Convert a 2D Python table to ASCII text
- .. versionchanged:: 1.0.0
- Added the ``use_wcwidth`` parameter defaulting to :py:obj:`True`.
-
Args:
header: 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.
@@ -660,8 +662,10 @@ 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]``). If not specified or set to
- :py:obj:`None`, all columns will be center-aligned. Defaults to :py:obj:`None`.
+ (ex. ``[Alignment.LEFT, Alignment.CENTER, Alignment.RIGHT, Alignment.DECIMAL]``)
+ or a single alignment to apply to all columns (ex. ``Alignment.LEFT``).
+ If not specified or set to :py:obj:`None`, all columns will be center-aligned.
+ Defaults to :py:obj:`None`.
cell_padding: The minimum number of spaces to add between the cell content and the column
separator. If set to ``0``, the cell content will be flush against the column separator.
Defaults to ``1``.
@@ -673,6 +677,14 @@ def table2ascii(
zero-width space, etc.), whereas :func:`len` determines the width solely based on the number of
characters in the string. Defaults to :py:obj:`True`.
+ .. versionchanged:: 1.1.0
+
+ ``alignments`` can now also be specified as a single :class:`Alignment` value to apply to all columns.
+
+ .. versionchanged:: 1.0.0
+
+ Added the ``use_wcwidth`` parameter defaulting to :py:obj:`True`.
+
Returns:
The generated ASCII table
"""
diff --git a/tests/test_alignments.py b/tests/test_alignments.py
index 107c32b..ff684e1 100644
--- a/tests/test_alignments.py
+++ b/tests/test_alignments.py
@@ -120,3 +120,37 @@ def test_decimal_alignment():
"╚═════════════╩═══════╧═════════════╧════╧════╧═════════╝"
)
assert text == expected
+
+
+def test_single_decimal_alignment():
+ text = t2a(
+ header=["1.1.1", "G", "Long Header"],
+ body=[[100.00001, 2, 3.14], [10.0001, 22.0, 2.718]],
+ alignments=Alignment.DECIMAL,
+ )
+ expected = (
+ "╔════════════════════════════════╗\n"
+ "║ 1.1.1 G Long Header ║\n"
+ "╟────────────────────────────────╢\n"
+ "║ 100.00001 2 3.14 ║\n"
+ "║ 10.0001 22.0 2.718 ║\n"
+ "╚════════════════════════════════╝"
+ )
+ assert text == expected
+
+
+def test_single_left_alignment():
+ text = t2a(
+ header=["1.1.1", "G", "Long Header"],
+ body=[[100.00001, 2, 3.14], [10.0001, 22.0, 2.718]],
+ alignments=Alignment.LEFT,
+ )
+ expected = (
+ "╔════════════════════════════════╗\n"
+ "║ 1.1.1 G Long Header ║\n"
+ "╟────────────────────────────────╢\n"
+ "║ 100.00001 2 3.14 ║\n"
+ "║ 10.0001 22.0 2.718 ║\n"
+ "╚════════════════════════════════╝"
+ )
+ assert text == expected
Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.
Alternative Proxies: