Skip to content

Commit

Permalink
Adding column_date_formats config option
Browse files Browse the repository at this point in the history
Allows per-column formatting for date, time, datetime like columns
  • Loading branch information
dougharris committed Mar 5, 2025
1 parent 4f214f6 commit 4fec88d
Show file tree
Hide file tree
Showing 5 changed files with 71 additions and 2 deletions.
1 change: 1 addition & 0 deletions AUTHORS
Original file line number Diff line number Diff line change
Expand Up @@ -138,6 +138,7 @@ Contributors:
* Mathieu Dupuy (deronnax)
* Chris Novakovic
* Josh Lynch (josh-lynch)
* Doug Harris (dougharris)

Creator:
--------
Expand Down
1 change: 1 addition & 0 deletions changelog.rst
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ Features
--------
* Add a `--ping` command line option; allows pgcli to replace `pg_isready`
* Changed the packaging metadata from setup.py to pyproject.toml
* Added support for per-column date/time formatting using `column_date_formats` in config

Bug fixes:
----------
Expand Down
15 changes: 13 additions & 2 deletions pgcli/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,11 @@
from typing import Optional

from cli_helpers.tabular_output import TabularOutputFormatter
from cli_helpers.tabular_output.preprocessors import align_decimals, format_numbers
from cli_helpers.tabular_output.preprocessors import (
align_decimals,
format_numbers,
format_timestamps,
)
from cli_helpers.utils import strip_ansi
from .explain_output_formatter import ExplainOutputFormatter
import click
Expand Down Expand Up @@ -111,12 +115,13 @@

OutputSettings = namedtuple(
"OutputSettings",
"table_format dcmlfmt floatfmt missingval expanded max_width case_function style_output max_field_width",
"table_format dcmlfmt floatfmt column_date_formats missingval expanded max_width case_function style_output max_field_width",
)
OutputSettings.__new__.__defaults__ = (
None,
None,
None,
None,
"<null>",
False,
None,
Expand Down Expand Up @@ -264,6 +269,7 @@ def __init__(
self.on_error = c["main"]["on_error"].upper()
self.decimal_format = c["data_formats"]["decimal"]
self.float_format = c["data_formats"]["float"]
self.column_date_formats = c["column_date_formats"]
auth.keyring_initialize(c["main"].as_bool("keyring"), logger=self.logger)
self.show_bottom_toolbar = c["main"].as_bool("show_bottom_toolbar")

Expand Down Expand Up @@ -1179,6 +1185,7 @@ def _evaluate_command(self, text):
table_format=self.table_format,
dcmlfmt=self.decimal_format,
floatfmt=self.float_format,
column_date_formats=self.column_date_formats,
missingval=self.null_string,
expanded=expanded,
max_width=max_width,
Expand Down Expand Up @@ -1830,6 +1837,7 @@ def format_status(cur, status):
"missing_value": settings.missingval,
"integer_format": settings.dcmlfmt,
"float_format": settings.floatfmt,
"column_date_formats": settings.column_date_formats,
"preprocessors": (format_numbers, format_arrays),
"disable_numparse": True,
"preserve_whitespace": True,
Expand All @@ -1839,6 +1847,9 @@ def format_status(cur, status):
if not settings.floatfmt:
output_kwargs["preprocessors"] = (align_decimals,)

if settings.column_date_formats:
output_kwargs["preprocessors"] += (format_timestamps,)

if table_format == "csv":
# The default CSV dialect is "excel" which is not handling newline values correctly
# Nevertheless, we want to keep on using "excel" on Windows since it uses '\r\n'
Expand Down
5 changes: 5 additions & 0 deletions pgcli/pgclirc
Original file line number Diff line number Diff line change
Expand Up @@ -240,3 +240,8 @@ output.null = "#808080"
[data_formats]
decimal = ""
float = ""

# Per column formats for date/timestamp columns
[column_date_formats]
# use strftime format, e.g.
# created = "%Y-%m-%d"
51 changes: 51 additions & 0 deletions tests/test_main.py
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,57 @@ def test_format_output():
assert list(results) == expected


def test_column_date_formats():
settings = OutputSettings(
table_format="psql",
column_date_formats={
"date_col": "%Y-%m-%d",
"datetime_col": "%I:%M:%S %m/%d/%y",
},
)
data = [
("name1", "2024-12-13T18:32:22", "2024-12-13T19:32:22", "2024-12-13T20:32:22"),
("name2", "2025-02-13T02:32:22", "2025-02-13T02:32:22", "2025-02-13T02:32:22"),
]
headers = ["name", "date_col", "datetime_col", "unchanged_col"]

results = format_output("Title", data, headers, "test status", settings)
expected = [
"Title",
"+-------+------------+-------------------+---------------------+",
"| name | date_col | datetime_col | unchanged_col |",
"|-------+------------+-------------------+---------------------|",
"| name1 | 2024-12-13 | 07:32:22 12/13/24 | 2024-12-13T20:32:22 |",
"| name2 | 2025-02-13 | 02:32:22 02/13/25 | 2025-02-13T02:32:22 |",
"+-------+------------+-------------------+---------------------+",
"test status",
]
assert list(results) == expected


def test_no_column_date_formats():
"""Test that not setting any column date formats returns unaltered datetime columns"""
settings = OutputSettings(table_format="psql")
data = [
("name1", "2024-12-13T18:32:22", "2024-12-13T19:32:22", "2024-12-13T20:32:22"),
("name2", "2025-02-13T02:32:22", "2025-02-13T02:32:22", "2025-02-13T02:32:22"),
]
headers = ["name", "date_col", "datetime_col", "unchanged_col"]

results = format_output("Title", data, headers, "test status", settings)
expected = [
"Title",
"+-------+---------------------+---------------------+---------------------+",
"| name | date_col | datetime_col | unchanged_col |",
"|-------+---------------------+---------------------+---------------------|",
"| name1 | 2024-12-13T18:32:22 | 2024-12-13T19:32:22 | 2024-12-13T20:32:22 |",
"| name2 | 2025-02-13T02:32:22 | 2025-02-13T02:32:22 | 2025-02-13T02:32:22 |",
"+-------+---------------------+---------------------+---------------------+",
"test status",
]
assert list(results) == expected


def test_format_output_truncate_on():
settings = OutputSettings(
table_format="psql", dcmlfmt="d", floatfmt="g", max_field_width=10
Expand Down

0 comments on commit 4fec88d

Please sign in to comment.