1
0
Fork 0

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
This commit is contained in:
Damien Baty 2024-02-19 09:36:46 +01:00
parent 96eb37fd19
commit 9f114c4549
5 changed files with 52 additions and 8 deletions

View File

@ -67,10 +67,6 @@ jobs:
psql -h localhost -U postgres -p 6432 pgbouncer -c 'show help' 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 - name: Install requirements
run: | run: |
pip install -U pip setuptools pip install -U pip setuptools

View File

@ -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 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 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)) * 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) 4.0.1 (2023-10-30)

View File

@ -11,7 +11,6 @@ import logging
import threading import threading
import shutil import shutil
import functools import functools
import pendulum
import datetime as dt import datetime as dt
import itertools import itertools
import platform import platform
@ -800,9 +799,9 @@ class PGCli:
"Time: %0.03fs (%s), executed in: %0.03fs (%s)" "Time: %0.03fs (%s), executed in: %0.03fs (%s)"
% ( % (
query.total_time, query.total_time,
pendulum.Duration(seconds=query.total_time).in_words(), duration_in_words(query.total_time),
query.execution_time, query.execution_time,
pendulum.Duration(seconds=query.execution_time).in_words(), duration_in_words(query.execution_time),
) )
) )
else: else:
@ -1735,5 +1734,28 @@ def parse_service_info(service):
return service_conf, service_file 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__": if __name__ == "__main__":
cli() cli()

View File

@ -16,7 +16,6 @@ install_requirements = [
"psycopg-binary >= 3.0.14; sys_platform == 'win32'", "psycopg-binary >= 3.0.14; sys_platform == 'win32'",
"sqlparse >=0.3.0,<0.5", "sqlparse >=0.3.0,<0.5",
"configobj >= 5.0.6", "configobj >= 5.0.6",
"pendulum>=2.1.0",
"cli_helpers[styles] >= 2.2.1", "cli_helpers[styles] >= 2.2.1",
] ]

View File

@ -11,6 +11,7 @@ except ImportError:
from pgcli.main import ( from pgcli.main import (
obfuscate_process_password, obfuscate_process_password,
duration_in_words,
format_output, format_output,
PGCli, PGCli,
OutputSettings, OutputSettings,
@ -488,3 +489,28 @@ def test_application_name_db_uri(tmpdir):
mock_pgexecute.assert_called_with( mock_pgexecute.assert_called_with(
"bar", "bar", "", "baz.com", "", "", application_name="cow" "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