Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions AUTHORS
Original file line number Diff line number Diff line change
Expand Up @@ -139,6 +139,7 @@ Contributors:
* Chris Novakovic
* Josh Lynch (josh-lynch)
* Fabio (3ximus)
* 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 @@ -6,6 +6,7 @@ Features
* Add a `--ping` command line option; allows pgcli to replace `pg_isready`
* Changed the packaging metadata from setup.py to pyproject.toml
* Add bash completion for services defined in the service file `~/.pg_service.conf`
* 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"
2 changes: 1 addition & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ dependencies = [
"psycopg-binary >= 3.0.14; sys_platform == 'win32'",
"sqlparse >=0.3.0,<0.6",
"configobj >= 5.0.6",
"cli_helpers[styles] >= 2.2.1",
"cli_helpers[styles] >= 2.4.0",
# setproctitle is used to mask the password when running `ps` in command line.
# But this is not necessary in Windows since the password is never shown in the
# task manager. Also setproctitle is a hard dependency to install in Windows,
Expand Down
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
Loading