summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDamien Baty <damien@damienbaty.com>2024-02-19 09:36:46 +0100
committerDamien Baty <damien@damienbaty.com>2024-02-20 12:51:20 +0100
commit9f114c4549c672c64cb5bb5b56f4fce725267fda (patch)
treeb2a70ba5cd0ef0cc93614a2671e0637f453b2249
parent96eb37fd1989ec8fd86150f20053abd03f50e7a4 (diff)
feat: Replace pendulum by home-made duration-to-words function
`pgcli` uses Pendulum to display the query execution time in words: > select pg_sleep(62) +----------+ | pg_sleep | |----------| | | +----------+ SELECT 1 Time: 62.066s (1 minute 2 seconds), executed in: 62.063s (1 minute 2 seconds) Pendulum 3 (which has been released in December 2023 and is now written in Rust) does not build on 32-bit architectures [1]. As such, installing `pgcli` on such architectures fails. We could pin Pendulum to version 2 (which was written in Python and builds "everywhere"), but requiring a whole library and its own dependencies for such a small feature seems unwarranted. This commit thus removes the requirement on Pendulum and replaces it by a simple "duration-to-words" function. Fixes #1451. [1] Upstream issue: https://github.com/sdispater/pendulum/issues/784
-rw-r--r--.github/workflows/ci.yml4
-rw-r--r--changelog.rst1
-rw-r--r--pgcli/main.py28
-rw-r--r--setup.py1
-rw-r--r--tests/test_main.py26
5 files changed, 52 insertions, 8 deletions
diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml
index 68a69acd..d9698ef4 100644
--- a/.github/workflows/ci.yml
+++ b/.github/workflows/ci.yml
@@ -67,10 +67,6 @@ jobs:
psql -h localhost -U postgres -p 6432 pgbouncer -c 'show help'
- - name: Install beta version of pendulum
- run: pip install pendulum==3.0.0b1
- if: matrix.python-version == '3.12'
-
- name: Install requirements
run: |
pip install -U pip setuptools
diff --git a/changelog.rst b/changelog.rst
index 9f0f573f..cb70bb8d 100644
--- a/changelog.rst
+++ b/changelog.rst
@@ -11,6 +11,7 @@ Bug fixes:
* Fix display of "short host" in prompt (with `\h`) for IPv4 addresses ([issue 964](https://github.com/dbcli/pgcli/issues/964)).
* Fix backwards display of NOTICEs from a Function ([issue 1443](https://github.com/dbcli/pgcli/issues/1443))
* Fix psycopg errors when installing on Windows. ([issue 1413](https://https://github.com/dbcli/pgcli/issues/1413))
+* Use a home-made function to display query duration instead of relying on a third-party library (the general behaviour does not change), which fixes the installation of `pgcli` on 32-bit architectures ([issue 1451](https://github.com/dbcli/pgcli/issues/1451))
==================
4.0.1 (2023-10-30)
diff --git a/pgcli/main.py b/pgcli/main.py
index bbb1989d..cfa1c970 100644
--- a/pgcli/main.py
+++ b/pgcli/main.py
@@ -11,7 +11,6 @@ import logging
import threading
import shutil
import functools
-import pendulum
import datetime as dt
import itertools
import platform
@@ -800,9 +799,9 @@ class PGCli:
"Time: %0.03fs (%s), executed in: %0.03fs (%s)"
% (
query.total_time,
- pendulum.Duration(seconds=query.total_time).in_words(),
+ duration_in_words(query.total_time),
query.execution_time,
- pendulum.Duration(seconds=query.execution_time).in_words(),
+ duration_in_words(query.execution_time),
)
)
else:
@@ -1735,5 +1734,28 @@ def parse_service_info(service):
return service_conf, service_file
+def duration_in_words(duration_in_seconds: float) -> str:
+ if not duration_in_seconds:
+ return "0 seconds"
+ components = []
+ hours, remainder = divmod(duration_in_seconds, 3600)
+ if hours > 1:
+ components.append(f"{hours} hours")
+ elif hours == 1:
+ components.append("1 hour")
+ minutes, seconds = divmod(remainder, 60)
+ if minutes > 1:
+ components.append(f"{minutes} minutes")
+ elif minutes == 1:
+ components.append("1 minute")
+ if seconds >= 2:
+ components.append(f"{int(seconds)} seconds")
+ elif seconds >= 1:
+ components.append("1 second")
+ elif seconds:
+ components.append(f"{round(seconds, 3)} second")
+ return " ".join(components)
+
+
if __name__ == "__main__":
cli()
diff --git a/setup.py b/setup.py
index f9dbc56a..640dca00 100644
--- a/setup.py
+++ b/setup.py
@@ -16,7 +16,6 @@ install_requirements = [
"psycopg-binary >= 3.0.14; sys_platform == 'win32'",
"sqlparse >=0.3.0,<0.5",
"configobj >= 5.0.6",
- "pendulum>=2.1.0",
"cli_helpers[styles] >= 2.2.1",
]
diff --git a/tests/test_main.py b/tests/test_main.py
index cbf20a6a..0aeba80e 100644
--- a/tests/test_main.py
+++ b/tests/test_main.py
@@ -11,6 +11,7 @@ except ImportError:
from pgcli.main import (
obfuscate_process_password,
+ duration_in_words,
format_output,
PGCli,
OutputSettings,
@@ -488,3 +489,28 @@ def test_application_name_db_uri(tmpdir):
mock_pgexecute.assert_called_with(
"bar", "bar", "", "baz.com", "", "", application_name="cow"
)
+
+
+@pytest.mark.parametrize(
+ "duration_in_seconds,words",
+ [
+ (0, "0 seconds"),
+ (0.0009, "0.001 second"),
+ (0.0005, "0.001 second"),
+ (0.0004, "0.0 second"), # not perfect, but will do
+ (0.2, "0.2 second"),
+ (1, "1 second"),
+ (1.4, "1 second"),
+ (2, "2 seconds"),
+ (3.4, "3 seconds"),
+ (60, "1 minute"),
+ (61, "1 minute 1 second"),
+ (123, "2 minutes 3 seconds"),
+ (3600, "1 hour"),
+ (7235, "2 hours 35 seconds"),
+ (9005, "2 hours 30 minutes 5 seconds"),
+ (86401, "24 hours 1 second"),
+ ],
+)
+def test_duration_in_words(duration_in_seconds, words):
+ assert duration_in_words(duration_in_seconds) == words