From 77d1c3386f18d48919c5be492e91debbe427134d Mon Sep 17 00:00:00 2001 From: Denis Laxalde Date: Fri, 19 Apr 2024 12:14:13 +0200 Subject: [PATCH] Add non-negative counterparts of --no-XXX options --- CHANGELOG.md | 3 + pgactivity/cli.py | 48 +++++----- pgactivity/config.py | 1 + tests/test_cli_help.txt | 92 +++++++++++++++++++ .../{test_cli.txt => test_cli_help_py38.txt} | 12 ++- 5 files changed, 132 insertions(+), 24 deletions(-) create mode 100644 tests/test_cli_help.txt rename tests/{test_cli.txt => test_cli_help_py38.txt} (92%) diff --git a/CHANGELOG.md b/CHANGELOG.md index 441b2692..1ab6d593 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,9 @@ * The color of cells in the process table can now be customized through the configuration file. +* Add non-negative counterparts of many `--no-...` command-line option, thus + allowing to enable respective feature/behaviour even if disabled in the + configuration. (This only works with Python 3.9 or higher.) ### Fixed diff --git a/pgactivity/cli.py b/pgactivity/cli.py index af5d111c..0ac06c4d 100755 --- a/pgactivity/cli.py +++ b/pgactivity/cli.py @@ -1,11 +1,11 @@ from __future__ import annotations +import argparse import logging import os import socket import sys import time -from argparse import ArgumentParser from io import StringIO from typing import Any @@ -45,12 +45,20 @@ def configure_logger(debug_file: str | None = None) -> StringIO: return memory_string -def flag(p: Any, spec: str, *, dest: str, help: str) -> None: - p.add_argument(spec, dest=dest, help=help, action="store_false", default=True) +def flag(p: Any, spec: str, *, dest: str, feature: str) -> None: + assert not spec.startswith("--no-") and spec.startswith("--"), spec + if sys.version_info < (3, 9): + spec = f"--no-{spec[2:]}" + action = "store_false" + help = f"Disable {feature}." + else: + action = argparse.BooleanOptionalAction + help = f"Enable/disable {feature} (default=%(default)s)." + p.add_argument(spec, dest=dest, help=help, action=action, default=True) -def get_parser() -> ArgumentParser: - parser = ArgumentParser( +def get_parser() -> argparse.ArgumentParser: + parser = argparse.ArgumentParser( usage="%(prog)s [options] [connection string]", description=( "htop like application for PostgreSQL server activity monitoring." @@ -103,11 +111,9 @@ def get_parser() -> ArgumentParser: metavar="FILEPATH", default=None, ) - flag(group, "--no-db-size", dest="dbsize", help="Skip total size of DB.") - flag( - group, "--no-tempfiles", dest="tempfiles", help="Skip tempfile count and size." - ) - flag(group, "--no-walreceiver", dest="walreceiver", help="Skip walreceiver checks.") + flag(group, "--db-size", dest="dbsize", feature="total size of DB") + flag(group, "--tempfiles", dest="tempfiles", feature="tempfile count and size") + flag(group, "--walreceiver", dest="walreceiver", feature="walreceiver checks") group.add_argument( "-w", "--wrap-query", @@ -215,17 +221,17 @@ def get_parser() -> ArgumentParser: "Process table display options", "These options may be used hide some columns from the processes table.", ) - flag(group, "--no-pid", dest="pid", help="Disable PID.") - flag(group, "--no-database", dest="database", help="Disable DATABASE.") - flag(group, "--no-user", dest="user", help="Disable USER.") - flag(group, "--no-client", dest="client", help="Disable CLIENT.") - flag(group, "--no-cpu", dest="cpu", help="Disable CPU%%.") - flag(group, "--no-mem", dest="mem", help="Disable MEM%%.") - flag(group, "--no-read", dest="read", help="Disable READ/s.") - flag(group, "--no-write", dest="write", help="Disable WRITE/s.") - flag(group, "--no-time", dest="time", help="Disable TIME+.") - flag(group, "--no-wait", dest="wait", help="Disable W.") - flag(group, "--no-app-name", dest="appname", help="Disable APP.") + flag(group, "--pid", dest="pid", feature="PID") + flag(group, "--database", dest="database", feature="DATABASE") + flag(group, "--user", dest="user", feature="USER") + flag(group, "--client", dest="client", feature="CLIENT") + flag(group, "--cpu", dest="cpu", feature="CPU%%") + flag(group, "--mem", dest="mem", feature="MEM%%") + flag(group, "--read", dest="read", feature="READ/s") + flag(group, "--write", dest="write", feature="WRITE/s") + flag(group, "--time", dest="time", feature="TIME+") + flag(group, "--wait", dest="wait", feature="W") + flag(group, "--app-name", dest="appname", feature="APP") group = parser.add_argument_group("Header display options") group.add_argument( diff --git a/pgactivity/config.py b/pgactivity/config.py index 4c481542..13a694c6 100644 --- a/pgactivity/config.py +++ b/pgactivity/config.py @@ -128,6 +128,7 @@ def load( flag = cls.from_config(config) else: flag = cls.all() + # TODO: handle truthy values, coming from, e.g., --pid if not pid: flag ^= cls.PID if not database: diff --git a/tests/test_cli_help.txt b/tests/test_cli_help.txt new file mode 100644 index 00000000..e1f0f090 --- /dev/null +++ b/tests/test_cli_help.txt @@ -0,0 +1,92 @@ +>>> import sys +>>> import pytest +>>> if sys.version_info < (3, 9): +... pytest.skip("only applies for Python version >= 3.9") +... + +>>> from pgactivity import cli +>>> parser = cli.get_parser() +>>> parser.print_help() +usage: pytest [options] [connection string] + +htop like application for PostgreSQL server activity monitoring. + +Configuration: + -P PROFILE, --profile PROFILE + Configuration profile matching a PROFILE.conf file in + ${XDG_CONFIG_HOME:~/.config}/pg_activity/ or + /etc/pg_activity/, or a built-in profile. + +Options: + --blocksize BLOCKSIZE + Filesystem blocksize (default: 4096). + --rds Enable support for AWS RDS (implies --no-tempfiles and + filters out the rdsadmin database from space + calculation). + --output FILEPATH Store running queries as CSV. + --db-size, --no-db-size + Enable/disable total size of DB (default=True). + --tempfiles, --no-tempfiles + Enable/disable tempfile count and size (default=True). + --walreceiver, --no-walreceiver + Enable/disable walreceiver checks (default=True). + -w, --wrap-query Wrap query column instead of truncating. + --duration-mode DURATION_MODE + Duration mode. Values: 1-QUERY(default), + 2-TRANSACTION, 3-BACKEND. + --min-duration SECONDS + Don't display queries with smaller than specified + duration (in seconds). + --filter FIELD:REGEX Filter activities with a (case insensitive) regular + expression applied on selected fields. Known fields + are: dbname. + --debug-file DEBUG_FILE + Enable debug and write it to DEBUG_FILE. + --version show program's version number and exit. + --help Show this help message and exit. + +Connection Options: + connection string A valid connection string to the database, e.g.: + 'host=HOSTNAME port=PORT user=USER dbname=DBNAME'. + -h HOSTNAME, --host HOSTNAME + Database server host or socket directory. + -p PORT, --port PORT Database server port. + -U USERNAME, --username USERNAME + Database user name. + -d DBNAME, --dbname DBNAME + Database name to connect to. + +Process table display options: + These options may be used hide some columns from the processes table. + + --pid, --no-pid Enable/disable PID (default=True). + --database, --no-database + Enable/disable DATABASE (default=True). + --user, --no-user Enable/disable USER (default=True). + --client, --no-client + Enable/disable CLIENT (default=True). + --cpu, --no-cpu Enable/disable CPU% (default=True). + --mem, --no-mem Enable/disable MEM% (default=True). + --read, --no-read Enable/disable READ/s (default=True). + --write, --no-write Enable/disable WRITE/s (default=True). + --time, --no-time Enable/disable TIME+ (default=True). + --wait, --no-wait Enable/disable W (default=True). + --app-name, --no-app-name + Enable/disable APP (default=True). + +Header display options: + --no-inst-info Hide instance information. + --no-sys-info Hide system information. + --no-proc-info Hide workers process information. + +Other display options: + --hide-queries-in-logs + Disable log_min_duration_statements and + log_min_duration_sample for pg_activity. + --refresh REFRESH Refresh rate. Values: 0.5, 1, 2, 3, 4, 5 (default: 2). + +The connection string can be in the form of a list of Key/Value parameters or +an URI as described in the PostgreSQL documentation. The parsing is delegated +to the libpq: different versions of the client library may support different +formats or parameters (for example, connection URIs are only supported from +libpq 9.2). diff --git a/tests/test_cli.txt b/tests/test_cli_help_py38.txt similarity index 92% rename from tests/test_cli.txt rename to tests/test_cli_help_py38.txt index b4013db1..48a3c46e 100644 --- a/tests/test_cli.txt +++ b/tests/test_cli_help_py38.txt @@ -1,3 +1,9 @@ +>>> import sys +>>> import pytest +>>> if sys.version_info >= (3, 9): +... pytest.skip("only applies for Python version < 3.9") +... + >>> from pgactivity import cli >>> parser = cli.get_parser() >>> parser.print_help() @@ -18,9 +24,9 @@ Options: filters out the rdsadmin database from space calculation). --output FILEPATH Store running queries as CSV. - --no-db-size Skip total size of DB. - --no-tempfiles Skip tempfile count and size. - --no-walreceiver Skip walreceiver checks. + --no-db-size Disable total size of DB. + --no-tempfiles Disable tempfile count and size. + --no-walreceiver Disable walreceiver checks. -w, --wrap-query Wrap query column instead of truncating. --duration-mode DURATION_MODE Duration mode. Values: 1-QUERY(default),