pgcli 4.1.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.
- {pgcli-4.1.0 → pgcli-4.3.0}/AUTHORS +7 -0
- {pgcli-4.1.0/pgcli.egg-info → pgcli-4.3.0}/PKG-INFO +17 -12
- {pgcli-4.1.0 → pgcli-4.3.0}/README.rst +6 -3
- {pgcli-4.1.0 → pgcli-4.3.0}/changelog.rst +27 -0
- pgcli-4.3.0/pgcli/__init__.py +1 -0
- {pgcli-4.1.0 → pgcli-4.3.0}/pgcli/main.py +96 -12
- {pgcli-4.1.0 → pgcli-4.3.0}/pgcli/pgclirc +9 -0
- {pgcli-4.1.0 → pgcli-4.3.0}/pgcli/pgcompleter.py +15 -8
- {pgcli-4.1.0 → pgcli-4.3.0}/pgcli/pgexecute.py +13 -0
- {pgcli-4.1.0 → pgcli-4.3.0/pgcli.egg-info}/PKG-INFO +17 -12
- {pgcli-4.1.0 → pgcli-4.3.0}/pgcli.egg-info/SOURCES.txt +0 -1
- pgcli-4.3.0/pgcli.egg-info/dependency_links.txt +1 -0
- {pgcli-4.1.0 → pgcli-4.3.0}/pgcli.egg-info/requires.txt +5 -2
- pgcli-4.3.0/pyproject.toml +94 -0
- {pgcli-4.1.0 → pgcli-4.3.0}/tests/features/basic_commands.feature +4 -0
- {pgcli-4.1.0 → pgcli-4.3.0}/tests/features/steps/basic_commands.py +13 -0
- {pgcli-4.1.0 → pgcli-4.3.0}/tests/test_main.py +51 -0
- {pgcli-4.1.0 → pgcli-4.3.0}/tests/test_pgcompleter.py +24 -0
- pgcli-4.1.0/pgcli/__init__.py +0 -1
- pgcli-4.1.0/pgcli.egg-info/dependency_links.txt +0 -1
- pgcli-4.1.0/pyproject.toml +0 -21
- pgcli-4.1.0/setup.py +0 -71
- {pgcli-4.1.0 → pgcli-4.3.0}/LICENSE.txt +0 -0
- {pgcli-4.1.0 → pgcli-4.3.0}/MANIFEST.in +0 -0
- {pgcli-4.1.0 → pgcli-4.3.0}/pgcli/__main__.py +0 -0
- {pgcli-4.1.0 → pgcli-4.3.0}/pgcli/auth.py +0 -0
- {pgcli-4.1.0 → pgcli-4.3.0}/pgcli/completion_refresher.py +0 -0
- {pgcli-4.1.0 → pgcli-4.3.0}/pgcli/config.py +0 -0
- {pgcli-4.1.0 → pgcli-4.3.0}/pgcli/explain_output_formatter.py +0 -0
- {pgcli-4.1.0 → pgcli-4.3.0}/pgcli/key_bindings.py +0 -0
- {pgcli-4.1.0 → pgcli-4.3.0}/pgcli/magic.py +0 -0
- {pgcli-4.1.0 → pgcli-4.3.0}/pgcli/packages/__init__.py +0 -0
- {pgcli-4.1.0 → pgcli-4.3.0}/pgcli/packages/formatter/__init__.py +0 -0
- {pgcli-4.1.0 → pgcli-4.3.0}/pgcli/packages/formatter/sqlformatter.py +0 -0
- {pgcli-4.1.0 → pgcli-4.3.0}/pgcli/packages/parseutils/__init__.py +0 -0
- {pgcli-4.1.0 → pgcli-4.3.0}/pgcli/packages/parseutils/ctes.py +0 -0
- {pgcli-4.1.0 → pgcli-4.3.0}/pgcli/packages/parseutils/meta.py +0 -0
- {pgcli-4.1.0 → pgcli-4.3.0}/pgcli/packages/parseutils/tables.py +0 -0
- {pgcli-4.1.0 → pgcli-4.3.0}/pgcli/packages/parseutils/utils.py +0 -0
- {pgcli-4.1.0 → pgcli-4.3.0}/pgcli/packages/pgliterals/__init__.py +0 -0
- {pgcli-4.1.0 → pgcli-4.3.0}/pgcli/packages/pgliterals/main.py +0 -0
- {pgcli-4.1.0 → pgcli-4.3.0}/pgcli/packages/pgliterals/pgliterals.json +0 -0
- {pgcli-4.1.0 → pgcli-4.3.0}/pgcli/packages/prioritization.py +0 -0
- {pgcli-4.1.0 → pgcli-4.3.0}/pgcli/packages/prompt_utils.py +0 -0
- {pgcli-4.1.0 → pgcli-4.3.0}/pgcli/packages/sqlcompletion.py +0 -0
- {pgcli-4.1.0 → pgcli-4.3.0}/pgcli/pgbuffer.py +0 -0
- {pgcli-4.1.0 → pgcli-4.3.0}/pgcli/pgstyle.py +0 -0
- {pgcli-4.1.0 → pgcli-4.3.0}/pgcli/pgtoolbar.py +0 -0
- {pgcli-4.1.0 → pgcli-4.3.0}/pgcli/pyev.py +0 -0
- {pgcli-4.1.0 → pgcli-4.3.0}/pgcli.egg-info/entry_points.txt +0 -0
- {pgcli-4.1.0 → pgcli-4.3.0}/pgcli.egg-info/top_level.txt +0 -0
- {pgcli-4.1.0 → pgcli-4.3.0}/setup.cfg +0 -0
- {pgcli-4.1.0 → pgcli-4.3.0}/tests/conftest.py +0 -0
- {pgcli-4.1.0 → pgcli-4.3.0}/tests/features/__init__.py +0 -0
- {pgcli-4.1.0 → pgcli-4.3.0}/tests/features/auto_vertical.feature +0 -0
- {pgcli-4.1.0 → pgcli-4.3.0}/tests/features/crud_database.feature +0 -0
- {pgcli-4.1.0 → pgcli-4.3.0}/tests/features/crud_table.feature +0 -0
- {pgcli-4.1.0 → pgcli-4.3.0}/tests/features/db_utils.py +0 -0
- {pgcli-4.1.0 → pgcli-4.3.0}/tests/features/environment.py +0 -0
- {pgcli-4.1.0 → pgcli-4.3.0}/tests/features/expanded.feature +0 -0
- {pgcli-4.1.0 → pgcli-4.3.0}/tests/features/fixture_data/help.txt +0 -0
- {pgcli-4.1.0 → pgcli-4.3.0}/tests/features/fixture_data/help_commands.txt +0 -0
- {pgcli-4.1.0 → pgcli-4.3.0}/tests/features/fixture_utils.py +0 -0
- {pgcli-4.1.0 → pgcli-4.3.0}/tests/features/iocommands.feature +0 -0
- {pgcli-4.1.0 → pgcli-4.3.0}/tests/features/named_queries.feature +0 -0
- {pgcli-4.1.0 → pgcli-4.3.0}/tests/features/pgbouncer.feature +0 -0
- {pgcli-4.1.0 → pgcli-4.3.0}/tests/features/specials.feature +0 -0
- {pgcli-4.1.0 → pgcli-4.3.0}/tests/features/steps/__init__.py +0 -0
- {pgcli-4.1.0 → pgcli-4.3.0}/tests/features/steps/auto_vertical.py +0 -0
- {pgcli-4.1.0 → pgcli-4.3.0}/tests/features/steps/crud_database.py +0 -0
- {pgcli-4.1.0 → pgcli-4.3.0}/tests/features/steps/crud_table.py +0 -0
- {pgcli-4.1.0 → pgcli-4.3.0}/tests/features/steps/expanded.py +0 -0
- {pgcli-4.1.0 → pgcli-4.3.0}/tests/features/steps/iocommands.py +0 -0
- {pgcli-4.1.0 → pgcli-4.3.0}/tests/features/steps/named_queries.py +0 -0
- {pgcli-4.1.0 → pgcli-4.3.0}/tests/features/steps/pgbouncer.py +0 -0
- {pgcli-4.1.0 → pgcli-4.3.0}/tests/features/steps/specials.py +0 -0
- {pgcli-4.1.0 → pgcli-4.3.0}/tests/features/steps/wrappers.py +0 -0
- {pgcli-4.1.0 → pgcli-4.3.0}/tests/features/wrappager.py +0 -0
- {pgcli-4.1.0 → pgcli-4.3.0}/tests/formatter/__init__.py +0 -0
- {pgcli-4.1.0 → pgcli-4.3.0}/tests/formatter/test_sqlformatter.py +0 -0
- {pgcli-4.1.0 → pgcli-4.3.0}/tests/metadata.py +0 -0
- {pgcli-4.1.0 → pgcli-4.3.0}/tests/parseutils/test_ctes.py +0 -0
- {pgcli-4.1.0 → pgcli-4.3.0}/tests/parseutils/test_function_metadata.py +0 -0
- {pgcli-4.1.0 → pgcli-4.3.0}/tests/parseutils/test_parseutils.py +0 -0
- {pgcli-4.1.0 → pgcli-4.3.0}/tests/pytest.ini +0 -0
- {pgcli-4.1.0 → pgcli-4.3.0}/tests/test_application_name.py +0 -0
- {pgcli-4.1.0 → pgcli-4.3.0}/tests/test_auth.py +0 -0
- {pgcli-4.1.0 → pgcli-4.3.0}/tests/test_completion_refresher.py +0 -0
- {pgcli-4.1.0 → pgcli-4.3.0}/tests/test_config.py +0 -0
- {pgcli-4.1.0 → pgcli-4.3.0}/tests/test_fuzzy_completion.py +0 -0
- {pgcli-4.1.0 → pgcli-4.3.0}/tests/test_naive_completion.py +0 -0
- {pgcli-4.1.0 → pgcli-4.3.0}/tests/test_pgexecute.py +0 -0
- {pgcli-4.1.0 → pgcli-4.3.0}/tests/test_pgspecial.py +0 -0
- {pgcli-4.1.0 → pgcli-4.3.0}/tests/test_prioritization.py +0 -0
- {pgcli-4.1.0 → pgcli-4.3.0}/tests/test_prompt_utils.py +0 -0
- {pgcli-4.1.0 → pgcli-4.3.0}/tests/test_rowlimit.py +0 -0
- {pgcli-4.1.0 → pgcli-4.3.0}/tests/test_smart_completion_multiple_schemata.py +0 -0
- {pgcli-4.1.0 → pgcli-4.3.0}/tests/test_smart_completion_public_schema_only.py +0 -0
- {pgcli-4.1.0 → pgcli-4.3.0}/tests/test_sqlcompletion.py +0 -0
- {pgcli-4.1.0 → pgcli-4.3.0}/tests/test_ssh_tunnel.py +0 -0
- {pgcli-4.1.0 → pgcli-4.3.0}/tests/utils.py +0 -0
|
@@ -134,6 +134,13 @@ Contributors:
|
|
|
134
134
|
* Antonio Aguilar (crazybolillo)
|
|
135
135
|
* Andrew M. MacFie (amacfie)
|
|
136
136
|
* saucoide
|
|
137
|
+
* Chris Rose (offbyone/offby1)
|
|
138
|
+
* Mathieu Dupuy (deronnax)
|
|
139
|
+
* Chris Novakovic
|
|
140
|
+
* Max Smolin (maximsmol)
|
|
141
|
+
* Josh Lynch (josh-lynch)
|
|
142
|
+
* Fabio (3ximus)
|
|
143
|
+
* Doug Harris (dougharris)
|
|
137
144
|
|
|
138
145
|
Creator:
|
|
139
146
|
--------
|
|
@@ -1,27 +1,27 @@
|
|
|
1
|
-
Metadata-Version: 2.
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
2
|
Name: pgcli
|
|
3
|
-
Version: 4.
|
|
3
|
+
Version: 4.3.0
|
|
4
4
|
Summary: CLI for Postgres Database. With auto-completion and syntax highlighting.
|
|
5
|
-
|
|
6
|
-
Author: Pgcli Core Team
|
|
7
|
-
Author-email: pgcli-dev@googlegroups.com
|
|
5
|
+
Author-email: Pgcli Core Team <pgcli-dev@googlegroups.com>
|
|
8
6
|
License: BSD
|
|
7
|
+
Project-URL: Homepage, https://pgcli.com
|
|
9
8
|
Classifier: Intended Audience :: Developers
|
|
10
9
|
Classifier: License :: OSI Approved :: BSD License
|
|
11
10
|
Classifier: Operating System :: Unix
|
|
12
11
|
Classifier: Programming Language :: Python
|
|
13
12
|
Classifier: Programming Language :: Python :: 3
|
|
14
|
-
Classifier: Programming Language :: Python :: 3.8
|
|
15
13
|
Classifier: Programming Language :: Python :: 3.9
|
|
16
14
|
Classifier: Programming Language :: Python :: 3.10
|
|
17
15
|
Classifier: Programming Language :: Python :: 3.11
|
|
18
16
|
Classifier: Programming Language :: Python :: 3.12
|
|
17
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
19
18
|
Classifier: Programming Language :: SQL
|
|
20
19
|
Classifier: Topic :: Database
|
|
21
20
|
Classifier: Topic :: Database :: Front-Ends
|
|
22
21
|
Classifier: Topic :: Software Development
|
|
23
22
|
Classifier: Topic :: Software Development :: Libraries :: Python Modules
|
|
24
|
-
Requires-Python: >=3.
|
|
23
|
+
Requires-Python: >=3.9
|
|
24
|
+
Description-Content-Type: text/x-rst
|
|
25
25
|
License-File: LICENSE.txt
|
|
26
26
|
License-File: AUTHORS
|
|
27
27
|
Requires-Dist: pgspecial>=2.0.0
|
|
@@ -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.
|
|
36
|
-
Requires-Dist: setproctitle>=1.1.9
|
|
35
|
+
Requires-Dist: cli_helpers[styles]>=2.4.0
|
|
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
|
---------------------
|
|
@@ -220,7 +222,7 @@ Alternatively, you can install ``pgcli`` as a python package using a package
|
|
|
220
222
|
manager called called ``pip``. You will need postgres installed on your system
|
|
221
223
|
for this to work.
|
|
222
224
|
|
|
223
|
-
In depth getting started guide for ``pip`` - https://pip.pypa.io/en/latest/
|
|
225
|
+
In depth getting started guide for ``pip`` - https://pip.pypa.io/en/latest/installation/
|
|
224
226
|
|
|
225
227
|
::
|
|
226
228
|
|
|
@@ -250,7 +252,7 @@ If pip is not installed check if easy_install is available on the system.
|
|
|
250
252
|
Linux:
|
|
251
253
|
======
|
|
252
254
|
|
|
253
|
-
In depth getting started guide for ``pip`` - https://pip.pypa.io/en/latest/
|
|
255
|
+
In depth getting started guide for ``pip`` - https://pip.pypa.io/en/latest/installation/
|
|
254
256
|
|
|
255
257
|
Check if pip is already available in your system.
|
|
256
258
|
|
|
@@ -393,7 +395,10 @@ choice:
|
|
|
393
395
|
|
|
394
396
|
In [3]: my_result = _
|
|
395
397
|
|
|
396
|
-
Pgcli dropped support for
|
|
398
|
+
Pgcli dropped support for:
|
|
399
|
+
|
|
400
|
+
* Python<3.8 as of 4.0.0.
|
|
401
|
+
* Python<3.9 as of 4.2.0.
|
|
397
402
|
|
|
398
403
|
Thanks:
|
|
399
404
|
-------
|
|
@@ -179,7 +179,7 @@ Alternatively, you can install ``pgcli`` as a python package using a package
|
|
|
179
179
|
manager called called ``pip``. You will need postgres installed on your system
|
|
180
180
|
for this to work.
|
|
181
181
|
|
|
182
|
-
In depth getting started guide for ``pip`` - https://pip.pypa.io/en/latest/
|
|
182
|
+
In depth getting started guide for ``pip`` - https://pip.pypa.io/en/latest/installation/
|
|
183
183
|
|
|
184
184
|
::
|
|
185
185
|
|
|
@@ -209,7 +209,7 @@ If pip is not installed check if easy_install is available on the system.
|
|
|
209
209
|
Linux:
|
|
210
210
|
======
|
|
211
211
|
|
|
212
|
-
In depth getting started guide for ``pip`` - https://pip.pypa.io/en/latest/
|
|
212
|
+
In depth getting started guide for ``pip`` - https://pip.pypa.io/en/latest/installation/
|
|
213
213
|
|
|
214
214
|
Check if pip is already available in your system.
|
|
215
215
|
|
|
@@ -352,7 +352,10 @@ choice:
|
|
|
352
352
|
|
|
353
353
|
In [3]: my_result = _
|
|
354
354
|
|
|
355
|
-
Pgcli dropped support for
|
|
355
|
+
Pgcli dropped support for:
|
|
356
|
+
|
|
357
|
+
* Python<3.8 as of 4.0.0.
|
|
358
|
+
* Python<3.9 as of 4.2.0.
|
|
356
359
|
|
|
357
360
|
Thanks:
|
|
358
361
|
-------
|
|
@@ -1,3 +1,30 @@
|
|
|
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
|
+
|
|
8
|
+
4.2.0 (2025-03-06)
|
|
9
|
+
==================
|
|
10
|
+
|
|
11
|
+
Features
|
|
12
|
+
--------
|
|
13
|
+
* Add a `--ping` command line option; allows pgcli to replace `pg_isready`
|
|
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
|
|
17
|
+
|
|
18
|
+
Bug fixes:
|
|
19
|
+
----------
|
|
20
|
+
* Avoid raising `NameError` when exiting unsuccessfully in some cases
|
|
21
|
+
* Use configured `alias_map_file` to generate table aliases if available.
|
|
22
|
+
|
|
23
|
+
Internal:
|
|
24
|
+
---------
|
|
25
|
+
|
|
26
|
+
* Drop support for Python 3.8 and add 3.13.
|
|
27
|
+
|
|
1
28
|
4.1.0 (2024-03-09)
|
|
2
29
|
==================
|
|
3
30
|
|
|
@@ -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
|
|
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
|
|
|
@@ -610,7 +618,7 @@ class PGCli:
|
|
|
610
618
|
click.secho(
|
|
611
619
|
f"service '{service}' was not found in {file}", err=True, fg="red"
|
|
612
620
|
)
|
|
613
|
-
exit(1)
|
|
621
|
+
sys.exit(1)
|
|
614
622
|
self.connect(
|
|
615
623
|
database=service_config.get("dbname"),
|
|
616
624
|
host=service_config.get("host"),
|
|
@@ -710,7 +718,7 @@ class PGCli:
|
|
|
710
718
|
self.logger.handlers = logger_handlers
|
|
711
719
|
self.logger.error("traceback: %r", traceback.format_exc())
|
|
712
720
|
click.secho(str(e), err=True, fg="red")
|
|
713
|
-
exit(1)
|
|
721
|
+
sys.exit(1)
|
|
714
722
|
self.logger.handlers = logger_handlers
|
|
715
723
|
|
|
716
724
|
atexit.register(self.ssh_tunnel.stop)
|
|
@@ -763,7 +771,7 @@ class PGCli:
|
|
|
763
771
|
self.logger.debug("Database connection failed: %r.", e)
|
|
764
772
|
self.logger.error("traceback: %r", traceback.format_exc())
|
|
765
773
|
click.secho(str(e), err=True, fg="red")
|
|
766
|
-
exit(1)
|
|
774
|
+
sys.exit(1)
|
|
767
775
|
|
|
768
776
|
self.pgexecute = pgexecute
|
|
769
777
|
|
|
@@ -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,
|
|
@@ -1463,6 +1472,13 @@ class PGCli:
|
|
|
1463
1472
|
is_flag=True,
|
|
1464
1473
|
help="list available databases, then exit.",
|
|
1465
1474
|
)
|
|
1475
|
+
@click.option(
|
|
1476
|
+
"--ping",
|
|
1477
|
+
"ping_database",
|
|
1478
|
+
is_flag=True,
|
|
1479
|
+
default=False,
|
|
1480
|
+
help="Check database connectivity, then exit.",
|
|
1481
|
+
)
|
|
1466
1482
|
@click.option(
|
|
1467
1483
|
"--auto-vertical-output",
|
|
1468
1484
|
is_flag=True,
|
|
@@ -1504,6 +1520,7 @@ def cli(
|
|
|
1504
1520
|
prompt,
|
|
1505
1521
|
prompt_dsn,
|
|
1506
1522
|
list_databases,
|
|
1523
|
+
ping_database,
|
|
1507
1524
|
auto_vertical_output,
|
|
1508
1525
|
list_dsn,
|
|
1509
1526
|
warn,
|
|
@@ -1543,7 +1560,7 @@ def cli(
|
|
|
1543
1560
|
err=True,
|
|
1544
1561
|
fg="red",
|
|
1545
1562
|
)
|
|
1546
|
-
exit(1)
|
|
1563
|
+
sys.exit(1)
|
|
1547
1564
|
|
|
1548
1565
|
if ssh_tunnel and not SSH_TUNNEL_SUPPORT:
|
|
1549
1566
|
click.secho(
|
|
@@ -1552,7 +1569,7 @@ def cli(
|
|
|
1552
1569
|
err=True,
|
|
1553
1570
|
fg="red",
|
|
1554
1571
|
)
|
|
1555
|
-
exit(1)
|
|
1572
|
+
sys.exit(1)
|
|
1556
1573
|
|
|
1557
1574
|
pgcli = PGCli(
|
|
1558
1575
|
prompt_passwd,
|
|
@@ -1581,13 +1598,13 @@ def cli(
|
|
|
1581
1598
|
service = database[8:]
|
|
1582
1599
|
elif os.getenv("PGSERVICE") is not None:
|
|
1583
1600
|
service = os.getenv("PGSERVICE")
|
|
1584
|
-
# because option --list or -l are not supposed to have a db name
|
|
1585
|
-
if list_databases:
|
|
1601
|
+
# because option --ping, --list or -l are not supposed to have a db name
|
|
1602
|
+
if list_databases or ping_database:
|
|
1586
1603
|
database = "postgres"
|
|
1587
1604
|
|
|
1605
|
+
cfg = load_config(pgclirc, config_full_path)
|
|
1588
1606
|
if dsn != "":
|
|
1589
1607
|
try:
|
|
1590
|
-
cfg = load_config(pgclirc, config_full_path)
|
|
1591
1608
|
dsn_config = cfg["alias_dsn"][dsn]
|
|
1592
1609
|
except KeyError:
|
|
1593
1610
|
click.secho(
|
|
@@ -1596,7 +1613,7 @@ def cli(
|
|
|
1596
1613
|
err=True,
|
|
1597
1614
|
fg="red",
|
|
1598
1615
|
)
|
|
1599
|
-
exit(1)
|
|
1616
|
+
sys.exit(1)
|
|
1600
1617
|
except Exception:
|
|
1601
1618
|
click.secho(
|
|
1602
1619
|
"Invalid DSNs found in the config file. "
|
|
@@ -1604,7 +1621,7 @@ def cli(
|
|
|
1604
1621
|
err=True,
|
|
1605
1622
|
fg="red",
|
|
1606
1623
|
)
|
|
1607
|
-
exit(1)
|
|
1624
|
+
sys.exit(1)
|
|
1608
1625
|
pgcli.connect_uri(dsn_config)
|
|
1609
1626
|
pgcli.dsn_alias = dsn
|
|
1610
1627
|
elif "://" in database:
|
|
@@ -1616,6 +1633,55 @@ def cli(
|
|
|
1616
1633
|
else:
|
|
1617
1634
|
pgcli.connect(database, host, user, port)
|
|
1618
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
|
+
|
|
1619
1685
|
if list_databases:
|
|
1620
1686
|
cur, headers, status = pgcli.pgexecute.full_databases()
|
|
1621
1687
|
|
|
@@ -1626,6 +1692,20 @@ def cli(
|
|
|
1626
1692
|
|
|
1627
1693
|
sys.exit(0)
|
|
1628
1694
|
|
|
1695
|
+
if ping_database:
|
|
1696
|
+
try:
|
|
1697
|
+
list(pgcli.pgexecute.run("SELECT 1"))
|
|
1698
|
+
except Exception:
|
|
1699
|
+
click.secho(
|
|
1700
|
+
"Could not connect to the database. Please check that the database is running.",
|
|
1701
|
+
err=True,
|
|
1702
|
+
fg="red",
|
|
1703
|
+
)
|
|
1704
|
+
sys.exit(1)
|
|
1705
|
+
else:
|
|
1706
|
+
click.echo("PONG")
|
|
1707
|
+
sys.exit(0)
|
|
1708
|
+
|
|
1629
1709
|
pgcli.logger.debug(
|
|
1630
1710
|
"Launch Params: \n" "\tdatabase: %r" "\tuser: %r" "\thost: %r" "\tport: %r",
|
|
1631
1711
|
database,
|
|
@@ -1808,6 +1888,7 @@ def format_output(title, cur, headers, status, settings, explain_mode=False):
|
|
|
1808
1888
|
"missing_value": settings.missingval,
|
|
1809
1889
|
"integer_format": settings.dcmlfmt,
|
|
1810
1890
|
"float_format": settings.floatfmt,
|
|
1891
|
+
"column_date_formats": settings.column_date_formats,
|
|
1811
1892
|
"preprocessors": (format_numbers, format_arrays),
|
|
1812
1893
|
"disable_numparse": True,
|
|
1813
1894
|
"preserve_whitespace": True,
|
|
@@ -1817,6 +1898,9 @@ def format_output(title, cur, headers, status, settings, explain_mode=False):
|
|
|
1817
1898
|
if not settings.floatfmt:
|
|
1818
1899
|
output_kwargs["preprocessors"] = (align_decimals,)
|
|
1819
1900
|
|
|
1901
|
+
if settings.column_date_formats:
|
|
1902
|
+
output_kwargs["preprocessors"] += (format_timestamps,)
|
|
1903
|
+
|
|
1820
1904
|
if table_format == "csv":
|
|
1821
1905
|
# The default CSV dialect is "excel" which is not handling newline values correctly
|
|
1822
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"
|
|
@@ -63,10 +63,17 @@ normalize_ref = lambda ref: ref if ref[0] == '"' else '"' + ref.lower() + '"'
|
|
|
63
63
|
|
|
64
64
|
|
|
65
65
|
def generate_alias(tbl, alias_map=None):
|
|
66
|
-
"""Generate a table alias
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
66
|
+
"""Generate a table alias.
|
|
67
|
+
|
|
68
|
+
Given a table name will return an alias for that table using the first of
|
|
69
|
+
the following options there's a match for.
|
|
70
|
+
|
|
71
|
+
1. The predefined alias for table defined in the alias_map.
|
|
72
|
+
2. All upper-case letters in the table name.
|
|
73
|
+
3. The first letter of the table name and all letters preceded by _
|
|
74
|
+
|
|
75
|
+
:param tbl: unescaped name of the table to alias
|
|
76
|
+
:param alias_map: optional mapping of predefined table aliases
|
|
70
77
|
"""
|
|
71
78
|
if alias_map and tbl in alias_map:
|
|
72
79
|
return alias_map[tbl]
|
|
@@ -528,7 +535,7 @@ class PGCompleter(Completer):
|
|
|
528
535
|
scoped_cols = self.populate_scoped_cols(tables, suggestion.local_tables)
|
|
529
536
|
|
|
530
537
|
def make_cand(name, ref):
|
|
531
|
-
synonyms = (name, generate_alias(self.case(name)))
|
|
538
|
+
synonyms = (name, generate_alias(self.case(name), alias_map=self.alias_map))
|
|
532
539
|
return Candidate(qualify(name, ref), 0, "column", synonyms)
|
|
533
540
|
|
|
534
541
|
def flat_cols():
|
|
@@ -601,7 +608,7 @@ class PGCompleter(Completer):
|
|
|
601
608
|
tbl = self.case(tbl)
|
|
602
609
|
tbls = {normalize_ref(t.ref) for t in tbls}
|
|
603
610
|
if self.generate_aliases:
|
|
604
|
-
tbl = generate_alias(self.unescape_name(tbl))
|
|
611
|
+
tbl = generate_alias(self.unescape_name(tbl), alias_map=self.alias_map)
|
|
605
612
|
if normalize_ref(tbl) not in tbls:
|
|
606
613
|
return tbl
|
|
607
614
|
elif tbl[0] == '"':
|
|
@@ -644,7 +651,7 @@ class PGCompleter(Completer):
|
|
|
644
651
|
join = "{0} ON {0}.{1} = {2}.{3}".format(
|
|
645
652
|
c(left.tbl), c(left.col), rtbl.ref, c(right.col)
|
|
646
653
|
)
|
|
647
|
-
alias = generate_alias(self.case(left.tbl))
|
|
654
|
+
alias = generate_alias(self.case(left.tbl), alias_map=self.alias_map)
|
|
648
655
|
synonyms = [
|
|
649
656
|
join,
|
|
650
657
|
"{0} ON {0}.{1} = {2}.{3}".format(
|
|
@@ -845,7 +852,7 @@ class PGCompleter(Completer):
|
|
|
845
852
|
cased_tbl = self.case(tbl.name)
|
|
846
853
|
if do_alias:
|
|
847
854
|
alias = self.alias(cased_tbl, suggestion.table_refs)
|
|
848
|
-
synonyms = (cased_tbl, generate_alias(cased_tbl))
|
|
855
|
+
synonyms = (cased_tbl, generate_alias(cased_tbl, alias_map=self.alias_map))
|
|
849
856
|
maybe_alias = (" " + alias) if do_alias else ""
|
|
850
857
|
maybe_schema = (self.case(tbl.schema) + ".") if tbl.schema else ""
|
|
851
858
|
suffix = self._arg_list_cache[arg_mode][tbl.meta] if arg_mode else ""
|
|
@@ -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,27 +1,27 @@
|
|
|
1
|
-
Metadata-Version: 2.
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
2
|
Name: pgcli
|
|
3
|
-
Version: 4.
|
|
3
|
+
Version: 4.3.0
|
|
4
4
|
Summary: CLI for Postgres Database. With auto-completion and syntax highlighting.
|
|
5
|
-
|
|
6
|
-
Author: Pgcli Core Team
|
|
7
|
-
Author-email: pgcli-dev@googlegroups.com
|
|
5
|
+
Author-email: Pgcli Core Team <pgcli-dev@googlegroups.com>
|
|
8
6
|
License: BSD
|
|
7
|
+
Project-URL: Homepage, https://pgcli.com
|
|
9
8
|
Classifier: Intended Audience :: Developers
|
|
10
9
|
Classifier: License :: OSI Approved :: BSD License
|
|
11
10
|
Classifier: Operating System :: Unix
|
|
12
11
|
Classifier: Programming Language :: Python
|
|
13
12
|
Classifier: Programming Language :: Python :: 3
|
|
14
|
-
Classifier: Programming Language :: Python :: 3.8
|
|
15
13
|
Classifier: Programming Language :: Python :: 3.9
|
|
16
14
|
Classifier: Programming Language :: Python :: 3.10
|
|
17
15
|
Classifier: Programming Language :: Python :: 3.11
|
|
18
16
|
Classifier: Programming Language :: Python :: 3.12
|
|
17
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
19
18
|
Classifier: Programming Language :: SQL
|
|
20
19
|
Classifier: Topic :: Database
|
|
21
20
|
Classifier: Topic :: Database :: Front-Ends
|
|
22
21
|
Classifier: Topic :: Software Development
|
|
23
22
|
Classifier: Topic :: Software Development :: Libraries :: Python Modules
|
|
24
|
-
Requires-Python: >=3.
|
|
23
|
+
Requires-Python: >=3.9
|
|
24
|
+
Description-Content-Type: text/x-rst
|
|
25
25
|
License-File: LICENSE.txt
|
|
26
26
|
License-File: AUTHORS
|
|
27
27
|
Requires-Dist: pgspecial>=2.0.0
|
|
@@ -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.
|
|
36
|
-
Requires-Dist: setproctitle>=1.1.9
|
|
35
|
+
Requires-Dist: cli_helpers[styles]>=2.4.0
|
|
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
|
---------------------
|
|
@@ -220,7 +222,7 @@ Alternatively, you can install ``pgcli`` as a python package using a package
|
|
|
220
222
|
manager called called ``pip``. You will need postgres installed on your system
|
|
221
223
|
for this to work.
|
|
222
224
|
|
|
223
|
-
In depth getting started guide for ``pip`` - https://pip.pypa.io/en/latest/
|
|
225
|
+
In depth getting started guide for ``pip`` - https://pip.pypa.io/en/latest/installation/
|
|
224
226
|
|
|
225
227
|
::
|
|
226
228
|
|
|
@@ -250,7 +252,7 @@ If pip is not installed check if easy_install is available on the system.
|
|
|
250
252
|
Linux:
|
|
251
253
|
======
|
|
252
254
|
|
|
253
|
-
In depth getting started guide for ``pip`` - https://pip.pypa.io/en/latest/
|
|
255
|
+
In depth getting started guide for ``pip`` - https://pip.pypa.io/en/latest/installation/
|
|
254
256
|
|
|
255
257
|
Check if pip is already available in your system.
|
|
256
258
|
|
|
@@ -393,7 +395,10 @@ choice:
|
|
|
393
395
|
|
|
394
396
|
In [3]: my_result = _
|
|
395
397
|
|
|
396
|
-
Pgcli dropped support for
|
|
398
|
+
Pgcli dropped support for:
|
|
399
|
+
|
|
400
|
+
* Python<3.8 as of 4.0.0.
|
|
401
|
+
* Python<3.9 as of 4.2.0.
|
|
397
402
|
|
|
398
403
|
Thanks:
|
|
399
404
|
-------
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
|
|
@@ -4,12 +4,15 @@ 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.
|
|
8
|
-
|
|
7
|
+
cli_helpers[styles]>=2.4.0
|
|
8
|
+
tzlocal>=5.2
|
|
9
9
|
|
|
10
10
|
[:sys_platform != "win32"]
|
|
11
11
|
psycopg>=3.0.14
|
|
12
12
|
|
|
13
|
+
[:sys_platform != "win32" and "CYGWIN" not in sys_platform]
|
|
14
|
+
setproctitle>=1.1.9
|
|
15
|
+
|
|
13
16
|
[:sys_platform == "win32"]
|
|
14
17
|
psycopg-binary>=3.0.14
|
|
15
18
|
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
[project]
|
|
2
|
+
name = "pgcli"
|
|
3
|
+
authors = [{ name = "Pgcli Core Team", email = "pgcli-dev@googlegroups.com" }]
|
|
4
|
+
license = { text = "BSD" }
|
|
5
|
+
description = "CLI for Postgres Database. With auto-completion and syntax highlighting."
|
|
6
|
+
readme = "README.rst"
|
|
7
|
+
classifiers = [
|
|
8
|
+
"Intended Audience :: Developers",
|
|
9
|
+
"License :: OSI Approved :: BSD License",
|
|
10
|
+
"Operating System :: Unix",
|
|
11
|
+
"Programming Language :: Python",
|
|
12
|
+
"Programming Language :: Python :: 3",
|
|
13
|
+
"Programming Language :: Python :: 3.9",
|
|
14
|
+
"Programming Language :: Python :: 3.10",
|
|
15
|
+
"Programming Language :: Python :: 3.11",
|
|
16
|
+
"Programming Language :: Python :: 3.12",
|
|
17
|
+
"Programming Language :: Python :: 3.13",
|
|
18
|
+
"Programming Language :: SQL",
|
|
19
|
+
"Topic :: Database",
|
|
20
|
+
"Topic :: Database :: Front-Ends",
|
|
21
|
+
"Topic :: Software Development",
|
|
22
|
+
"Topic :: Software Development :: Libraries :: Python Modules",
|
|
23
|
+
]
|
|
24
|
+
urls = { Homepage = "https://pgcli.com" }
|
|
25
|
+
requires-python = ">=3.9"
|
|
26
|
+
dependencies = [
|
|
27
|
+
"pgspecial>=2.0.0",
|
|
28
|
+
"click >= 4.1",
|
|
29
|
+
"Pygments>=2.0", # Pygments has to be Capitalcased. WTF?
|
|
30
|
+
# We still need to use pt-2 unless pt-3 released on Fedora32
|
|
31
|
+
# see: https://github.com/dbcli/pgcli/pull/1197
|
|
32
|
+
"prompt_toolkit>=2.0.6,<4.0.0",
|
|
33
|
+
"psycopg >= 3.0.14; sys_platform != 'win32'",
|
|
34
|
+
"psycopg-binary >= 3.0.14; sys_platform == 'win32'",
|
|
35
|
+
"sqlparse >=0.3.0,<0.6",
|
|
36
|
+
"configobj >= 5.0.6",
|
|
37
|
+
"cli_helpers[styles] >= 2.4.0",
|
|
38
|
+
# setproctitle is used to mask the password when running `ps` in command line.
|
|
39
|
+
# But this is not necessary in Windows since the password is never shown in the
|
|
40
|
+
# task manager. Also setproctitle is a hard dependency to install in Windows,
|
|
41
|
+
# so we'll only install it if we're not in Windows.
|
|
42
|
+
"setproctitle >= 1.1.9; sys_platform != 'win32' and 'CYGWIN' not in sys_platform",
|
|
43
|
+
"tzlocal >= 5.2",
|
|
44
|
+
]
|
|
45
|
+
dynamic = ["version"]
|
|
46
|
+
|
|
47
|
+
|
|
48
|
+
[project.scripts]
|
|
49
|
+
pgcli = "pgcli.main:cli"
|
|
50
|
+
|
|
51
|
+
[project.optional-dependencies]
|
|
52
|
+
keyring = ["keyring >= 12.2.0"]
|
|
53
|
+
sshtunnel = ["sshtunnel >= 0.4.0"]
|
|
54
|
+
|
|
55
|
+
[build-system]
|
|
56
|
+
requires = ["setuptools>=61.2"]
|
|
57
|
+
build-backend = "setuptools.build_meta"
|
|
58
|
+
|
|
59
|
+
[tool.setuptools]
|
|
60
|
+
include-package-data = false
|
|
61
|
+
|
|
62
|
+
[tool.setuptools.dynamic]
|
|
63
|
+
version = { attr = "pgcli.__version__" }
|
|
64
|
+
|
|
65
|
+
[tool.setuptools.packages]
|
|
66
|
+
find = { namespaces = false }
|
|
67
|
+
|
|
68
|
+
[tool.setuptools.package-data]
|
|
69
|
+
pgcli = [
|
|
70
|
+
"pgclirc",
|
|
71
|
+
"packages/pgliterals/pgliterals.json",
|
|
72
|
+
]
|
|
73
|
+
|
|
74
|
+
[tool.black]
|
|
75
|
+
line-length = 88
|
|
76
|
+
target-version = ['py38']
|
|
77
|
+
include = '\.pyi?$'
|
|
78
|
+
exclude = '''
|
|
79
|
+
/(
|
|
80
|
+
\.eggs
|
|
81
|
+
| \.git
|
|
82
|
+
| \.hg
|
|
83
|
+
| \.mypy_cache
|
|
84
|
+
| \.tox
|
|
85
|
+
| \.venv
|
|
86
|
+
| \.cache
|
|
87
|
+
| \.pytest_cache
|
|
88
|
+
| _build
|
|
89
|
+
| buck-out
|
|
90
|
+
| build
|
|
91
|
+
| dist
|
|
92
|
+
| tests/data
|
|
93
|
+
)/
|
|
94
|
+
'''
|
|
@@ -51,6 +51,10 @@ Feature: run the cli,
|
|
|
51
51
|
When we list databases
|
|
52
52
|
then we see list of databases
|
|
53
53
|
|
|
54
|
+
Scenario: ping databases
|
|
55
|
+
When we ping the database
|
|
56
|
+
then we get a pong response
|
|
57
|
+
|
|
54
58
|
Scenario: run the cli with --username
|
|
55
59
|
When we launch dbcli using --username
|
|
56
60
|
and we send "\?" command
|
|
@@ -26,6 +26,19 @@ def step_see_list_databases(context):
|
|
|
26
26
|
context.cmd_output = None
|
|
27
27
|
|
|
28
28
|
|
|
29
|
+
@when("we ping the database")
|
|
30
|
+
def step_ping_database(context):
|
|
31
|
+
cmd = ["pgcli", "--ping"]
|
|
32
|
+
context.cmd_output = subprocess.check_output(cmd, cwd=context.package_root)
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
@then("we get a pong response")
|
|
36
|
+
def step_get_pong_response(context):
|
|
37
|
+
# exit code 0 is implied by the presence of cmd_output here, which
|
|
38
|
+
# is only set on a successful run.
|
|
39
|
+
assert context.cmd_output.strip() == b"PONG", f"Output was {context.cmd_output}"
|
|
40
|
+
|
|
41
|
+
|
|
29
42
|
@when("we run dbcli")
|
|
30
43
|
def step_run_cli(context):
|
|
31
44
|
wrappers.run_cli(context)
|
|
@@ -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,5 +1,7 @@
|
|
|
1
|
+
import json
|
|
1
2
|
import pytest
|
|
2
3
|
from pgcli import pgcompleter
|
|
4
|
+
import tempfile
|
|
3
5
|
|
|
4
6
|
|
|
5
7
|
def test_load_alias_map_file_missing_file():
|
|
@@ -47,12 +49,34 @@ def test_generate_alias_uses_first_char_and_every_preceded_by_underscore(
|
|
|
47
49
|
"table_name, alias_map, alias",
|
|
48
50
|
[
|
|
49
51
|
("some_table", {"some_table": "my_alias"}, "my_alias"),
|
|
52
|
+
pytest.param(
|
|
53
|
+
"some_other_table", {"some_table": "my_alias"}, "sot", id="no_match_in_map"
|
|
54
|
+
),
|
|
50
55
|
],
|
|
51
56
|
)
|
|
52
57
|
def test_generate_alias_can_use_alias_map(table_name, alias_map, alias):
|
|
53
58
|
assert pgcompleter.generate_alias(table_name, alias_map) == alias
|
|
54
59
|
|
|
55
60
|
|
|
61
|
+
@pytest.mark.parametrize(
|
|
62
|
+
"table_name, alias_map, alias",
|
|
63
|
+
[
|
|
64
|
+
("some_table", {"some_table": "my_alias"}, "my_alias"),
|
|
65
|
+
],
|
|
66
|
+
)
|
|
67
|
+
def test_pgcompleter_alias_uses_configured_alias_map(table_name, alias_map, alias):
|
|
68
|
+
with tempfile.NamedTemporaryFile(mode="w", suffix=".json") as alias_map_file:
|
|
69
|
+
alias_map_file.write(json.dumps(alias_map))
|
|
70
|
+
alias_map_file.seek(0)
|
|
71
|
+
completer = pgcompleter.PGCompleter(
|
|
72
|
+
settings={
|
|
73
|
+
"generate_aliases": True,
|
|
74
|
+
"alias_map_file": alias_map_file.name,
|
|
75
|
+
}
|
|
76
|
+
)
|
|
77
|
+
assert completer.alias(table_name, []) == alias
|
|
78
|
+
|
|
79
|
+
|
|
56
80
|
@pytest.mark.parametrize(
|
|
57
81
|
"table_name, alias_map, alias",
|
|
58
82
|
[
|
pgcli-4.1.0/pgcli/__init__.py
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
__version__ = "4.1.0"
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
http://github.com/psycopg/repo/tarball/master#egg=psycopg-3.0.10
|
pgcli-4.1.0/pyproject.toml
DELETED
|
@@ -1,21 +0,0 @@
|
|
|
1
|
-
[tool.black]
|
|
2
|
-
line-length = 88
|
|
3
|
-
target-version = ['py38']
|
|
4
|
-
include = '\.pyi?$'
|
|
5
|
-
exclude = '''
|
|
6
|
-
/(
|
|
7
|
-
\.eggs
|
|
8
|
-
| \.git
|
|
9
|
-
| \.hg
|
|
10
|
-
| \.mypy_cache
|
|
11
|
-
| \.tox
|
|
12
|
-
| \.venv
|
|
13
|
-
| \.cache
|
|
14
|
-
| \.pytest_cache
|
|
15
|
-
| _build
|
|
16
|
-
| buck-out
|
|
17
|
-
| build
|
|
18
|
-
| dist
|
|
19
|
-
| tests/data
|
|
20
|
-
)/
|
|
21
|
-
'''
|
pgcli-4.1.0/setup.py
DELETED
|
@@ -1,71 +0,0 @@
|
|
|
1
|
-
import platform
|
|
2
|
-
from setuptools import setup, find_packages
|
|
3
|
-
|
|
4
|
-
from pgcli import __version__
|
|
5
|
-
|
|
6
|
-
description = "CLI for Postgres Database. With auto-completion and syntax highlighting."
|
|
7
|
-
|
|
8
|
-
install_requirements = [
|
|
9
|
-
"pgspecial>=2.0.0",
|
|
10
|
-
"click >= 4.1",
|
|
11
|
-
"Pygments>=2.0", # Pygments has to be Capitalcased. WTF?
|
|
12
|
-
# We still need to use pt-2 unless pt-3 released on Fedora32
|
|
13
|
-
# see: https://github.com/dbcli/pgcli/pull/1197
|
|
14
|
-
"prompt_toolkit>=2.0.6,<4.0.0",
|
|
15
|
-
"psycopg >= 3.0.14; sys_platform != 'win32'",
|
|
16
|
-
"psycopg-binary >= 3.0.14; sys_platform == 'win32'",
|
|
17
|
-
"sqlparse >=0.3.0,<0.6",
|
|
18
|
-
"configobj >= 5.0.6",
|
|
19
|
-
"cli_helpers[styles] >= 2.2.1",
|
|
20
|
-
]
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
# setproctitle is used to mask the password when running `ps` in command line.
|
|
24
|
-
# But this is not necessary in Windows since the password is never shown in the
|
|
25
|
-
# task manager. Also setproctitle is a hard dependency to install in Windows,
|
|
26
|
-
# so we'll only install it if we're not in Windows.
|
|
27
|
-
if platform.system() != "Windows" and not platform.system().startswith("CYGWIN"):
|
|
28
|
-
install_requirements.append("setproctitle >= 1.1.9")
|
|
29
|
-
|
|
30
|
-
setup(
|
|
31
|
-
name="pgcli",
|
|
32
|
-
author="Pgcli Core Team",
|
|
33
|
-
author_email="pgcli-dev@googlegroups.com",
|
|
34
|
-
version=__version__,
|
|
35
|
-
license="BSD",
|
|
36
|
-
url="http://pgcli.com",
|
|
37
|
-
packages=find_packages(),
|
|
38
|
-
package_data={"pgcli": ["pgclirc", "packages/pgliterals/pgliterals.json"]},
|
|
39
|
-
description=description,
|
|
40
|
-
long_description=open("README.rst").read(),
|
|
41
|
-
install_requires=install_requirements,
|
|
42
|
-
dependency_links=[
|
|
43
|
-
"http://github.com/psycopg/repo/tarball/master#egg=psycopg-3.0.10"
|
|
44
|
-
],
|
|
45
|
-
extras_require={
|
|
46
|
-
"keyring": ["keyring >= 12.2.0"],
|
|
47
|
-
"sshtunnel": ["sshtunnel >= 0.4.0"],
|
|
48
|
-
},
|
|
49
|
-
python_requires=">=3.8",
|
|
50
|
-
entry_points="""
|
|
51
|
-
[console_scripts]
|
|
52
|
-
pgcli=pgcli.main:cli
|
|
53
|
-
""",
|
|
54
|
-
classifiers=[
|
|
55
|
-
"Intended Audience :: Developers",
|
|
56
|
-
"License :: OSI Approved :: BSD License",
|
|
57
|
-
"Operating System :: Unix",
|
|
58
|
-
"Programming Language :: Python",
|
|
59
|
-
"Programming Language :: Python :: 3",
|
|
60
|
-
"Programming Language :: Python :: 3.8",
|
|
61
|
-
"Programming Language :: Python :: 3.9",
|
|
62
|
-
"Programming Language :: Python :: 3.10",
|
|
63
|
-
"Programming Language :: Python :: 3.11",
|
|
64
|
-
"Programming Language :: Python :: 3.12",
|
|
65
|
-
"Programming Language :: SQL",
|
|
66
|
-
"Topic :: Database",
|
|
67
|
-
"Topic :: Database :: Front-Ends",
|
|
68
|
-
"Topic :: Software Development",
|
|
69
|
-
"Topic :: Software Development :: Libraries :: Python Modules",
|
|
70
|
-
],
|
|
71
|
-
)
|
|
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
|
|
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
|
|
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
|