pgcli 4.2.0__tar.gz → 4.3.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (98) hide show
  1. {pgcli-4.2.0 → pgcli-4.3.0}/AUTHORS +3 -0
  2. {pgcli-4.2.0/pgcli.egg-info → pgcli-4.3.0}/PKG-INFO +5 -3
  3. {pgcli-4.2.0 → pgcli-4.3.0}/changelog.rst +9 -0
  4. pgcli-4.3.0/pgcli/__init__.py +1 -0
  5. {pgcli-4.2.0 → pgcli-4.3.0}/pgcli/main.py +65 -3
  6. {pgcli-4.2.0 → pgcli-4.3.0}/pgcli/pgclirc +9 -0
  7. {pgcli-4.2.0 → pgcli-4.3.0}/pgcli/pgexecute.py +13 -0
  8. {pgcli-4.2.0 → pgcli-4.3.0/pgcli.egg-info}/PKG-INFO +5 -3
  9. {pgcli-4.2.0 → pgcli-4.3.0}/pgcli.egg-info/requires.txt +2 -1
  10. {pgcli-4.2.0 → pgcli-4.3.0}/pyproject.toml +2 -1
  11. {pgcli-4.2.0 → pgcli-4.3.0}/tests/test_main.py +51 -0
  12. pgcli-4.2.0/pgcli/__init__.py +0 -1
  13. {pgcli-4.2.0 → pgcli-4.3.0}/LICENSE.txt +0 -0
  14. {pgcli-4.2.0 → pgcli-4.3.0}/MANIFEST.in +0 -0
  15. {pgcli-4.2.0 → pgcli-4.3.0}/README.rst +0 -0
  16. {pgcli-4.2.0 → pgcli-4.3.0}/pgcli/__main__.py +0 -0
  17. {pgcli-4.2.0 → pgcli-4.3.0}/pgcli/auth.py +0 -0
  18. {pgcli-4.2.0 → pgcli-4.3.0}/pgcli/completion_refresher.py +0 -0
  19. {pgcli-4.2.0 → pgcli-4.3.0}/pgcli/config.py +0 -0
  20. {pgcli-4.2.0 → pgcli-4.3.0}/pgcli/explain_output_formatter.py +0 -0
  21. {pgcli-4.2.0 → pgcli-4.3.0}/pgcli/key_bindings.py +0 -0
  22. {pgcli-4.2.0 → pgcli-4.3.0}/pgcli/magic.py +0 -0
  23. {pgcli-4.2.0 → pgcli-4.3.0}/pgcli/packages/__init__.py +0 -0
  24. {pgcli-4.2.0 → pgcli-4.3.0}/pgcli/packages/formatter/__init__.py +0 -0
  25. {pgcli-4.2.0 → pgcli-4.3.0}/pgcli/packages/formatter/sqlformatter.py +0 -0
  26. {pgcli-4.2.0 → pgcli-4.3.0}/pgcli/packages/parseutils/__init__.py +0 -0
  27. {pgcli-4.2.0 → pgcli-4.3.0}/pgcli/packages/parseutils/ctes.py +0 -0
  28. {pgcli-4.2.0 → pgcli-4.3.0}/pgcli/packages/parseutils/meta.py +0 -0
  29. {pgcli-4.2.0 → pgcli-4.3.0}/pgcli/packages/parseutils/tables.py +0 -0
  30. {pgcli-4.2.0 → pgcli-4.3.0}/pgcli/packages/parseutils/utils.py +0 -0
  31. {pgcli-4.2.0 → pgcli-4.3.0}/pgcli/packages/pgliterals/__init__.py +0 -0
  32. {pgcli-4.2.0 → pgcli-4.3.0}/pgcli/packages/pgliterals/main.py +0 -0
  33. {pgcli-4.2.0 → pgcli-4.3.0}/pgcli/packages/pgliterals/pgliterals.json +0 -0
  34. {pgcli-4.2.0 → pgcli-4.3.0}/pgcli/packages/prioritization.py +0 -0
  35. {pgcli-4.2.0 → pgcli-4.3.0}/pgcli/packages/prompt_utils.py +0 -0
  36. {pgcli-4.2.0 → pgcli-4.3.0}/pgcli/packages/sqlcompletion.py +0 -0
  37. {pgcli-4.2.0 → pgcli-4.3.0}/pgcli/pgbuffer.py +0 -0
  38. {pgcli-4.2.0 → pgcli-4.3.0}/pgcli/pgcompleter.py +0 -0
  39. {pgcli-4.2.0 → pgcli-4.3.0}/pgcli/pgstyle.py +0 -0
  40. {pgcli-4.2.0 → pgcli-4.3.0}/pgcli/pgtoolbar.py +0 -0
  41. {pgcli-4.2.0 → pgcli-4.3.0}/pgcli/pyev.py +0 -0
  42. {pgcli-4.2.0 → pgcli-4.3.0}/pgcli.egg-info/SOURCES.txt +0 -0
  43. {pgcli-4.2.0 → pgcli-4.3.0}/pgcli.egg-info/dependency_links.txt +0 -0
  44. {pgcli-4.2.0 → pgcli-4.3.0}/pgcli.egg-info/entry_points.txt +0 -0
  45. {pgcli-4.2.0 → pgcli-4.3.0}/pgcli.egg-info/top_level.txt +0 -0
  46. {pgcli-4.2.0 → pgcli-4.3.0}/setup.cfg +0 -0
  47. {pgcli-4.2.0 → pgcli-4.3.0}/tests/conftest.py +0 -0
  48. {pgcli-4.2.0 → pgcli-4.3.0}/tests/features/__init__.py +0 -0
  49. {pgcli-4.2.0 → pgcli-4.3.0}/tests/features/auto_vertical.feature +0 -0
  50. {pgcli-4.2.0 → pgcli-4.3.0}/tests/features/basic_commands.feature +0 -0
  51. {pgcli-4.2.0 → pgcli-4.3.0}/tests/features/crud_database.feature +0 -0
  52. {pgcli-4.2.0 → pgcli-4.3.0}/tests/features/crud_table.feature +0 -0
  53. {pgcli-4.2.0 → pgcli-4.3.0}/tests/features/db_utils.py +0 -0
  54. {pgcli-4.2.0 → pgcli-4.3.0}/tests/features/environment.py +0 -0
  55. {pgcli-4.2.0 → pgcli-4.3.0}/tests/features/expanded.feature +0 -0
  56. {pgcli-4.2.0 → pgcli-4.3.0}/tests/features/fixture_data/help.txt +0 -0
  57. {pgcli-4.2.0 → pgcli-4.3.0}/tests/features/fixture_data/help_commands.txt +0 -0
  58. {pgcli-4.2.0 → pgcli-4.3.0}/tests/features/fixture_utils.py +0 -0
  59. {pgcli-4.2.0 → pgcli-4.3.0}/tests/features/iocommands.feature +0 -0
  60. {pgcli-4.2.0 → pgcli-4.3.0}/tests/features/named_queries.feature +0 -0
  61. {pgcli-4.2.0 → pgcli-4.3.0}/tests/features/pgbouncer.feature +0 -0
  62. {pgcli-4.2.0 → pgcli-4.3.0}/tests/features/specials.feature +0 -0
  63. {pgcli-4.2.0 → pgcli-4.3.0}/tests/features/steps/__init__.py +0 -0
  64. {pgcli-4.2.0 → pgcli-4.3.0}/tests/features/steps/auto_vertical.py +0 -0
  65. {pgcli-4.2.0 → pgcli-4.3.0}/tests/features/steps/basic_commands.py +0 -0
  66. {pgcli-4.2.0 → pgcli-4.3.0}/tests/features/steps/crud_database.py +0 -0
  67. {pgcli-4.2.0 → pgcli-4.3.0}/tests/features/steps/crud_table.py +0 -0
  68. {pgcli-4.2.0 → pgcli-4.3.0}/tests/features/steps/expanded.py +0 -0
  69. {pgcli-4.2.0 → pgcli-4.3.0}/tests/features/steps/iocommands.py +0 -0
  70. {pgcli-4.2.0 → pgcli-4.3.0}/tests/features/steps/named_queries.py +0 -0
  71. {pgcli-4.2.0 → pgcli-4.3.0}/tests/features/steps/pgbouncer.py +0 -0
  72. {pgcli-4.2.0 → pgcli-4.3.0}/tests/features/steps/specials.py +0 -0
  73. {pgcli-4.2.0 → pgcli-4.3.0}/tests/features/steps/wrappers.py +0 -0
  74. {pgcli-4.2.0 → pgcli-4.3.0}/tests/features/wrappager.py +0 -0
  75. {pgcli-4.2.0 → pgcli-4.3.0}/tests/formatter/__init__.py +0 -0
  76. {pgcli-4.2.0 → pgcli-4.3.0}/tests/formatter/test_sqlformatter.py +0 -0
  77. {pgcli-4.2.0 → pgcli-4.3.0}/tests/metadata.py +0 -0
  78. {pgcli-4.2.0 → pgcli-4.3.0}/tests/parseutils/test_ctes.py +0 -0
  79. {pgcli-4.2.0 → pgcli-4.3.0}/tests/parseutils/test_function_metadata.py +0 -0
  80. {pgcli-4.2.0 → pgcli-4.3.0}/tests/parseutils/test_parseutils.py +0 -0
  81. {pgcli-4.2.0 → pgcli-4.3.0}/tests/pytest.ini +0 -0
  82. {pgcli-4.2.0 → pgcli-4.3.0}/tests/test_application_name.py +0 -0
  83. {pgcli-4.2.0 → pgcli-4.3.0}/tests/test_auth.py +0 -0
  84. {pgcli-4.2.0 → pgcli-4.3.0}/tests/test_completion_refresher.py +0 -0
  85. {pgcli-4.2.0 → pgcli-4.3.0}/tests/test_config.py +0 -0
  86. {pgcli-4.2.0 → pgcli-4.3.0}/tests/test_fuzzy_completion.py +0 -0
  87. {pgcli-4.2.0 → pgcli-4.3.0}/tests/test_naive_completion.py +0 -0
  88. {pgcli-4.2.0 → pgcli-4.3.0}/tests/test_pgcompleter.py +0 -0
  89. {pgcli-4.2.0 → pgcli-4.3.0}/tests/test_pgexecute.py +0 -0
  90. {pgcli-4.2.0 → pgcli-4.3.0}/tests/test_pgspecial.py +0 -0
  91. {pgcli-4.2.0 → pgcli-4.3.0}/tests/test_prioritization.py +0 -0
  92. {pgcli-4.2.0 → pgcli-4.3.0}/tests/test_prompt_utils.py +0 -0
  93. {pgcli-4.2.0 → pgcli-4.3.0}/tests/test_rowlimit.py +0 -0
  94. {pgcli-4.2.0 → pgcli-4.3.0}/tests/test_smart_completion_multiple_schemata.py +0 -0
  95. {pgcli-4.2.0 → pgcli-4.3.0}/tests/test_smart_completion_public_schema_only.py +0 -0
  96. {pgcli-4.2.0 → pgcli-4.3.0}/tests/test_sqlcompletion.py +0 -0
  97. {pgcli-4.2.0 → pgcli-4.3.0}/tests/test_ssh_tunnel.py +0 -0
  98. {pgcli-4.2.0 → pgcli-4.3.0}/tests/utils.py +0 -0
@@ -137,7 +137,10 @@ Contributors:
137
137
  * Chris Rose (offbyone/offby1)
138
138
  * Mathieu Dupuy (deronnax)
139
139
  * Chris Novakovic
140
+ * Max Smolin (maximsmol)
140
141
  * Josh Lynch (josh-lynch)
142
+ * Fabio (3ximus)
143
+ * Doug Harris (dougharris)
141
144
 
142
145
  Creator:
143
146
  --------
@@ -1,6 +1,6 @@
1
- Metadata-Version: 2.2
1
+ Metadata-Version: 2.4
2
2
  Name: pgcli
3
- Version: 4.2.0
3
+ Version: 4.3.0
4
4
  Summary: CLI for Postgres Database. With auto-completion and syntax highlighting.
5
5
  Author-email: Pgcli Core Team <pgcli-dev@googlegroups.com>
6
6
  License: BSD
@@ -32,12 +32,14 @@ Requires-Dist: psycopg>=3.0.14; sys_platform != "win32"
32
32
  Requires-Dist: psycopg-binary>=3.0.14; sys_platform == "win32"
33
33
  Requires-Dist: sqlparse<0.6,>=0.3.0
34
34
  Requires-Dist: configobj>=5.0.6
35
- Requires-Dist: cli_helpers[styles]>=2.2.1
35
+ Requires-Dist: cli_helpers[styles]>=2.4.0
36
36
  Requires-Dist: setproctitle>=1.1.9; sys_platform != "win32" and "CYGWIN" not in sys_platform
37
+ Requires-Dist: tzlocal>=5.2
37
38
  Provides-Extra: keyring
38
39
  Requires-Dist: keyring>=12.2.0; extra == "keyring"
39
40
  Provides-Extra: sshtunnel
40
41
  Requires-Dist: sshtunnel>=0.4.0; extra == "sshtunnel"
42
+ Dynamic: license-file
41
43
 
42
44
  We stand with Ukraine
43
45
  ---------------------
@@ -1,3 +1,10 @@
1
+ 4.3.0 (2025-03-22)
2
+ ==================
3
+
4
+ Features
5
+ --------
6
+ * The session time zone setting is set to the system time zone by default
7
+
1
8
  4.2.0 (2025-03-06)
2
9
  ==================
3
10
 
@@ -5,6 +12,8 @@ Features
5
12
  --------
6
13
  * Add a `--ping` command line option; allows pgcli to replace `pg_isready`
7
14
  * Changed the packaging metadata from setup.py to pyproject.toml
15
+ * Add bash completion for services defined in the service file `~/.pg_service.conf`
16
+ * Added support for per-column date/time formatting using `column_date_formats` in config
8
17
 
9
18
  Bug fixes:
10
19
  ----------
@@ -0,0 +1 @@
1
+ __version__ = "4.3.0"
@@ -1,3 +1,4 @@
1
+ from zoneinfo import ZoneInfoNotFoundError
1
2
  from configobj import ConfigObj, ParseError
2
3
  from pgspecial.namedqueries import NamedQueries
3
4
  from .config import skip_initial_comment
@@ -19,10 +20,15 @@ from time import time, sleep
19
20
  from typing import Optional
20
21
 
21
22
  from cli_helpers.tabular_output import TabularOutputFormatter
22
- from cli_helpers.tabular_output.preprocessors import align_decimals, format_numbers
23
+ from cli_helpers.tabular_output.preprocessors import (
24
+ align_decimals,
25
+ format_numbers,
26
+ format_timestamps,
27
+ )
23
28
  from cli_helpers.utils import strip_ansi
24
29
  from .explain_output_formatter import ExplainOutputFormatter
25
30
  import click
31
+ import tzlocal
26
32
 
27
33
  try:
28
34
  import setproctitle
@@ -111,12 +117,13 @@ MetaQuery.__new__.__defaults__ = ("", False, 0, 0, False, False, False, False)
111
117
 
112
118
  OutputSettings = namedtuple(
113
119
  "OutputSettings",
114
- "table_format dcmlfmt floatfmt missingval expanded max_width case_function style_output max_field_width",
120
+ "table_format dcmlfmt floatfmt column_date_formats missingval expanded max_width case_function style_output max_field_width",
115
121
  )
116
122
  OutputSettings.__new__.__defaults__ = (
117
123
  None,
118
124
  None,
119
125
  None,
126
+ None,
120
127
  "<null>",
121
128
  False,
122
129
  None,
@@ -264,6 +271,7 @@ class PGCli:
264
271
  self.on_error = c["main"]["on_error"].upper()
265
272
  self.decimal_format = c["data_formats"]["decimal"]
266
273
  self.float_format = c["data_formats"]["float"]
274
+ self.column_date_formats = c["column_date_formats"]
267
275
  auth.keyring_initialize(c["main"].as_bool("keyring"), logger=self.logger)
268
276
  self.show_bottom_toolbar = c["main"].as_bool("show_bottom_toolbar")
269
277
 
@@ -1179,6 +1187,7 @@ class PGCli:
1179
1187
  table_format=self.table_format,
1180
1188
  dcmlfmt=self.decimal_format,
1181
1189
  floatfmt=self.float_format,
1190
+ column_date_formats=self.column_date_formats,
1182
1191
  missingval=self.null_string,
1183
1192
  expanded=expanded,
1184
1193
  max_width=max_width,
@@ -1593,9 +1602,9 @@ def cli(
1593
1602
  if list_databases or ping_database:
1594
1603
  database = "postgres"
1595
1604
 
1605
+ cfg = load_config(pgclirc, config_full_path)
1596
1606
  if dsn != "":
1597
1607
  try:
1598
- cfg = load_config(pgclirc, config_full_path)
1599
1608
  dsn_config = cfg["alias_dsn"][dsn]
1600
1609
  except KeyError:
1601
1610
  click.secho(
@@ -1624,6 +1633,55 @@ def cli(
1624
1633
  else:
1625
1634
  pgcli.connect(database, host, user, port)
1626
1635
 
1636
+ if "use_local_timezone" not in cfg["main"] or cfg["main"].as_bool(
1637
+ "use_local_timezone"
1638
+ ):
1639
+ server_tz = pgcli.pgexecute.get_timezone()
1640
+
1641
+ def echo_error(msg: str):
1642
+ click.secho(
1643
+ "Failed to determine the local time zone",
1644
+ err=True,
1645
+ fg="yellow",
1646
+ )
1647
+ click.secho(
1648
+ msg,
1649
+ err=True,
1650
+ fg="yellow",
1651
+ )
1652
+ click.secho(
1653
+ f"Continuing with the default time zone as preset by the server ({server_tz})",
1654
+ err=True,
1655
+ fg="yellow",
1656
+ )
1657
+ click.secho(
1658
+ "Set `use_local_timezone = False` in the config to avoid trying to override the server time zone\n",
1659
+ err=True,
1660
+ dim=True,
1661
+ )
1662
+
1663
+ local_tz = None
1664
+ try:
1665
+ local_tz = tzlocal.get_localzone_name()
1666
+
1667
+ if local_tz is None:
1668
+ echo_error("No local time zone configuration found\n")
1669
+ else:
1670
+ click.secho(
1671
+ f"Using local time zone {local_tz} (server uses {server_tz})",
1672
+ fg="green",
1673
+ )
1674
+ click.secho(
1675
+ "Use `set time zone <TZ>` to override, or set `use_local_timezone = False` in the config",
1676
+ dim=True,
1677
+ )
1678
+
1679
+ pgcli.pgexecute.set_timezone(local_tz)
1680
+ except ZoneInfoNotFoundError as e:
1681
+ # e.args[0] is the pre-formatted message which includes a list
1682
+ # of conflicting sources
1683
+ echo_error(e.args[0])
1684
+
1627
1685
  if list_databases:
1628
1686
  cur, headers, status = pgcli.pgexecute.full_databases()
1629
1687
 
@@ -1830,6 +1888,7 @@ def format_output(title, cur, headers, status, settings, explain_mode=False):
1830
1888
  "missing_value": settings.missingval,
1831
1889
  "integer_format": settings.dcmlfmt,
1832
1890
  "float_format": settings.floatfmt,
1891
+ "column_date_formats": settings.column_date_formats,
1833
1892
  "preprocessors": (format_numbers, format_arrays),
1834
1893
  "disable_numparse": True,
1835
1894
  "preserve_whitespace": True,
@@ -1839,6 +1898,9 @@ def format_output(title, cur, headers, status, settings, explain_mode=False):
1839
1898
  if not settings.floatfmt:
1840
1899
  output_kwargs["preprocessors"] = (align_decimals,)
1841
1900
 
1901
+ if settings.column_date_formats:
1902
+ output_kwargs["preprocessors"] += (format_timestamps,)
1903
+
1842
1904
  if table_format == "csv":
1843
1905
  # The default CSV dialect is "excel" which is not handling newline values correctly
1844
1906
  # Nevertheless, we want to keep on using "excel" on Windows since it uses '\r\n'
@@ -191,6 +191,10 @@ enable_pager = True
191
191
  # Use keyring to automatically save and load password in a secure manner
192
192
  keyring = True
193
193
 
194
+ # Automatically set the session time zone to the local time zone
195
+ # If unset, uses the server's time zone, which is the Postgres default
196
+ use_local_timezone = True
197
+
194
198
  # Custom colors for the completion menu, toolbar, etc.
195
199
  [colors]
196
200
  completion-menu.completion.current = 'bg:#ffffff #000000'
@@ -240,3 +244,8 @@ output.null = "#808080"
240
244
  [data_formats]
241
245
  decimal = ""
242
246
  float = ""
247
+
248
+ # Per column formats for date/timestamp columns
249
+ [column_date_formats]
250
+ # use strftime format, e.g.
251
+ # created = "%Y-%m-%d"
@@ -881,3 +881,16 @@ class PGExecute:
881
881
 
882
882
  def explain_prefix(self):
883
883
  return "EXPLAIN (ANALYZE, COSTS, VERBOSE, BUFFERS, FORMAT JSON) "
884
+
885
+ def get_timezone(self) -> str:
886
+ query = psycopg.sql.SQL("show time zone")
887
+ with self.conn.cursor() as cur:
888
+ cur.execute(query)
889
+ return cur.fetchone()[0]
890
+
891
+ def set_timezone(self, timezone: str):
892
+ query = psycopg.sql.SQL("set time zone {}").format(
893
+ psycopg.sql.Identifier(timezone)
894
+ )
895
+ with self.conn.cursor() as cur:
896
+ cur.execute(query)
@@ -1,6 +1,6 @@
1
- Metadata-Version: 2.2
1
+ Metadata-Version: 2.4
2
2
  Name: pgcli
3
- Version: 4.2.0
3
+ Version: 4.3.0
4
4
  Summary: CLI for Postgres Database. With auto-completion and syntax highlighting.
5
5
  Author-email: Pgcli Core Team <pgcli-dev@googlegroups.com>
6
6
  License: BSD
@@ -32,12 +32,14 @@ Requires-Dist: psycopg>=3.0.14; sys_platform != "win32"
32
32
  Requires-Dist: psycopg-binary>=3.0.14; sys_platform == "win32"
33
33
  Requires-Dist: sqlparse<0.6,>=0.3.0
34
34
  Requires-Dist: configobj>=5.0.6
35
- Requires-Dist: cli_helpers[styles]>=2.2.1
35
+ Requires-Dist: cli_helpers[styles]>=2.4.0
36
36
  Requires-Dist: setproctitle>=1.1.9; sys_platform != "win32" and "CYGWIN" not in sys_platform
37
+ Requires-Dist: tzlocal>=5.2
37
38
  Provides-Extra: keyring
38
39
  Requires-Dist: keyring>=12.2.0; extra == "keyring"
39
40
  Provides-Extra: sshtunnel
40
41
  Requires-Dist: sshtunnel>=0.4.0; extra == "sshtunnel"
42
+ Dynamic: license-file
41
43
 
42
44
  We stand with Ukraine
43
45
  ---------------------
@@ -4,7 +4,8 @@ Pygments>=2.0
4
4
  prompt_toolkit<4.0.0,>=2.0.6
5
5
  sqlparse<0.6,>=0.3.0
6
6
  configobj>=5.0.6
7
- cli_helpers[styles]>=2.2.1
7
+ cli_helpers[styles]>=2.4.0
8
+ tzlocal>=5.2
8
9
 
9
10
  [:sys_platform != "win32"]
10
11
  psycopg>=3.0.14
@@ -34,12 +34,13 @@ dependencies = [
34
34
  "psycopg-binary >= 3.0.14; sys_platform == 'win32'",
35
35
  "sqlparse >=0.3.0,<0.6",
36
36
  "configobj >= 5.0.6",
37
- "cli_helpers[styles] >= 2.2.1",
37
+ "cli_helpers[styles] >= 2.4.0",
38
38
  # setproctitle is used to mask the password when running `ps` in command line.
39
39
  # But this is not necessary in Windows since the password is never shown in the
40
40
  # task manager. Also setproctitle is a hard dependency to install in Windows,
41
41
  # so we'll only install it if we're not in Windows.
42
42
  "setproctitle >= 1.1.9; sys_platform != 'win32' and 'CYGWIN' not in sys_platform",
43
+ "tzlocal >= 5.2",
43
44
  ]
44
45
  dynamic = ["version"]
45
46
 
@@ -76,6 +76,57 @@ def test_format_output():
76
76
  assert list(results) == expected
77
77
 
78
78
 
79
+ def test_column_date_formats():
80
+ settings = OutputSettings(
81
+ table_format="psql",
82
+ column_date_formats={
83
+ "date_col": "%Y-%m-%d",
84
+ "datetime_col": "%I:%M:%S %m/%d/%y",
85
+ },
86
+ )
87
+ data = [
88
+ ("name1", "2024-12-13T18:32:22", "2024-12-13T19:32:22", "2024-12-13T20:32:22"),
89
+ ("name2", "2025-02-13T02:32:22", "2025-02-13T02:32:22", "2025-02-13T02:32:22"),
90
+ ]
91
+ headers = ["name", "date_col", "datetime_col", "unchanged_col"]
92
+
93
+ results = format_output("Title", data, headers, "test status", settings)
94
+ expected = [
95
+ "Title",
96
+ "+-------+------------+-------------------+---------------------+",
97
+ "| name | date_col | datetime_col | unchanged_col |",
98
+ "|-------+------------+-------------------+---------------------|",
99
+ "| name1 | 2024-12-13 | 07:32:22 12/13/24 | 2024-12-13T20:32:22 |",
100
+ "| name2 | 2025-02-13 | 02:32:22 02/13/25 | 2025-02-13T02:32:22 |",
101
+ "+-------+------------+-------------------+---------------------+",
102
+ "test status",
103
+ ]
104
+ assert list(results) == expected
105
+
106
+
107
+ def test_no_column_date_formats():
108
+ """Test that not setting any column date formats returns unaltered datetime columns"""
109
+ settings = OutputSettings(table_format="psql")
110
+ data = [
111
+ ("name1", "2024-12-13T18:32:22", "2024-12-13T19:32:22", "2024-12-13T20:32:22"),
112
+ ("name2", "2025-02-13T02:32:22", "2025-02-13T02:32:22", "2025-02-13T02:32:22"),
113
+ ]
114
+ headers = ["name", "date_col", "datetime_col", "unchanged_col"]
115
+
116
+ results = format_output("Title", data, headers, "test status", settings)
117
+ expected = [
118
+ "Title",
119
+ "+-------+---------------------+---------------------+---------------------+",
120
+ "| name | date_col | datetime_col | unchanged_col |",
121
+ "|-------+---------------------+---------------------+---------------------|",
122
+ "| name1 | 2024-12-13T18:32:22 | 2024-12-13T19:32:22 | 2024-12-13T20:32:22 |",
123
+ "| name2 | 2025-02-13T02:32:22 | 2025-02-13T02:32:22 | 2025-02-13T02:32:22 |",
124
+ "+-------+---------------------+---------------------+---------------------+",
125
+ "test status",
126
+ ]
127
+ assert list(results) == expected
128
+
129
+
79
130
  def test_format_output_truncate_on():
80
131
  settings = OutputSettings(
81
132
  table_format="psql", dcmlfmt="d", floatfmt="g", max_field_width=10
@@ -1 +0,0 @@
1
- __version__ = "4.2.0"
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes