Skip to content

Commit

Permalink
Move UI header options into a dedicated class
Browse files Browse the repository at this point in the history
We introduce UIHeader class to hold header-specific options. Options
destinations are also renamed, to use a header_ prefix and to make the
action more explicit.
  • Loading branch information
dlax committed Feb 21, 2024
1 parent 1266368 commit f651a49
Show file tree
Hide file tree
Showing 7 changed files with 96 additions and 83 deletions.
6 changes: 3 additions & 3 deletions pgactivity/cli.py
Original file line number Diff line number Diff line change
Expand Up @@ -319,23 +319,23 @@ def get_parser() -> ArgumentParser:
# --no-inst-info
group.add_argument(
"--no-inst-info",
dest="show_instance_info_in_header",
dest="header_show_instance",
action="store_false",
help="Hide instance information.",
default=True,
)
# --no-sys-info
group.add_argument(
"--no-sys-info",
dest="show_system_info_in_header",
dest="header_show_system",
action="store_false",
help="Hide system information.",
default=True,
)
# --no-proc-info
group.add_argument(
"--no-proc-info",
dest="show_worker_info_in_header",
dest="header_show_workers",
action="store_false",
help="Hide workers process information.",
default=True,
Expand Down
12 changes: 6 additions & 6 deletions pgactivity/keys.py
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ def __eq__(self, other: Any) -> bool:
SORTBY_CPU = "c"
HEADER_TOGGLE_SYSTEM = "s"
HEADER_TOGGLE_INSTANCE = "i"
HEADER_TOGGLE_WORKER = "o"
HEADER_TOGGLE_WORKERS = "o"


def is_process_next(key: Keystroke) -> bool:
Expand Down Expand Up @@ -84,16 +84,16 @@ def is_process_last(key: Keystroke) -> bool:
return key.name == PROCESS_LAST


def is_toggle_header_sys_info(key: Keystroke) -> bool:
def is_toggle_header_system(key: Keystroke) -> bool:
return key == HEADER_TOGGLE_SYSTEM


def is_toggle_header_inst_info(key: Keystroke) -> bool:
def is_toggle_header_instance(key: Keystroke) -> bool:
return key == HEADER_TOGGLE_INSTANCE


def is_toggle_header_worker_info(key: Keystroke) -> bool:
return key == HEADER_TOGGLE_WORKER
def is_toggle_header_workers(key: Keystroke) -> bool:
return key == HEADER_TOGGLE_WORKERS


EXIT_KEY = Key(EXIT, "quit")
Expand All @@ -115,7 +115,7 @@ def is_toggle_header_worker_info(key: Keystroke) -> bool:
Key("R", "force refresh"),
Key(HEADER_TOGGLE_SYSTEM, "Display system information in header", local_only=True),
Key(HEADER_TOGGLE_INSTANCE, "Display general instance information in header"),
Key(HEADER_TOGGLE_WORKER, "Display worker information in header"),
Key(HEADER_TOGGLE_WORKERS, "Display worker information in header"),
EXIT_KEY,
]

Expand Down
109 changes: 60 additions & 49 deletions pgactivity/types.py
Original file line number Diff line number Diff line change
Expand Up @@ -193,10 +193,65 @@ def color(self, value: Any) -> str:
return self.color_key


@attr.s(auto_attribs=True, slots=True)
class UIHeader:
"""Configuration for the header of the UI."""

show_instance: bool = True
show_system: bool = True
show_workers: bool = True

def toggle_system(self) -> None:
"""Toggle the 'show_system' attribute.
>>> h = UIHeader()
>>> h.show_system
True
>>> h.toggle_system()
>>> h.show_system
False
>>> h.toggle_system()
>>> h.show_system
True
"""
self.show_system = not self.show_system

def toggle_instance(self) -> None:
"""Toggle the 'show_instance' attribute.
>>> h = UIHeader()
>>> h.show_instance
True
>>> h.toggle_instance()
>>> h.show_instance
False
>>> h.toggle_instance()
>>> h.show_instance
True
"""
self.show_instance = not self.show_instance

def toggle_workers(self) -> None:
"""Toggle the 'show_workers' attribute.
>>> h = UIHeader()
>>> h.show_workers
True
>>> h.toggle_workers()
>>> h.show_workers
False
>>> h.toggle_workers()
>>> h.show_workers
True
"""
self.show_workers = not self.show_workers


@attr.s(auto_attribs=True, slots=True)
class UI:
"""State of the UI."""

header: UIHeader
columns_by_querymode: Mapping[QueryMode, tuple[Column, ...]]
min_duration: float = 0.0
duration_mode: DurationMode = attr.ib(
Expand All @@ -208,20 +263,21 @@ class UI:
refresh_time: float | int = 2
in_pause: bool = False
interactive_timeout: int | None = None
show_instance_info_in_header: bool = True
show_system_info_in_header: bool = True
show_worker_info_in_header: bool = True

@classmethod
def make(
cls,
header: UIHeader | None = None,
config: Configuration | None = None,
flag: Flag = Flag.all(),
*,
max_db_length: int = 16,
filters: Filters = NO_FILTER,
**kwargs: Any,
) -> UI:
if header is None:
header = UIHeader()

possible_columns: dict[str, Column] = {}

def add_column(key: str, name: str, **kwargs: Any) -> None:
Expand Down Expand Up @@ -429,7 +485,7 @@ def make_columns_for(query_mode: QueryMode) -> Iterator[Column]:
pass

columns_by_querymode = {qm: tuple(make_columns_for(qm)) for qm in QueryMode}
return cls(columns_by_querymode=columns_by_querymode, **kwargs)
return cls(header=header, columns_by_querymode=columns_by_querymode, **kwargs)

def interactive(self) -> bool:
return self.interactive_timeout is not None
Expand Down Expand Up @@ -500,51 +556,6 @@ def toggle_pause(self) -> None:
"""
self.in_pause = not self.in_pause

def toggle_system_info_in_header(self) -> None:
"""Toggle the 'show_system_info_in_header' attribute.
>>> ui = UI.make()
>>> ui.show_system_info_in_header
True
>>> ui.toggle_system_info_in_header()
>>> ui.show_system_info_in_header
False
>>> ui.toggle_system_info_in_header()
>>> ui.show_system_info_in_header
True
"""
self.show_system_info_in_header = not self.show_system_info_in_header

def toggle_instance_info_in_header(self) -> None:
"""Toggle the 'show_instance_info_in_header' attribute.
>>> ui = UI.make()
>>> ui.show_instance_info_in_header
True
>>> ui.toggle_instance_info_in_header()
>>> ui.show_instance_info_in_header
False
>>> ui.toggle_instance_info_in_header()
>>> ui.show_instance_info_in_header
True
"""
self.show_instance_info_in_header = not self.show_instance_info_in_header

def toggle_worker_info_in_header(self) -> None:
"""Toggle the 'show_worker_info_in_header' attribute.
>>> ui = UI.make()
>>> ui.show_worker_info_in_header
True
>>> ui.toggle_worker_info_in_header()
>>> ui.show_worker_info_in_header
False
>>> ui.toggle_worker_info_in_header()
>>> ui.show_worker_info_in_header
True
"""
self.show_worker_info_in_header = not self.show_worker_info_in_header

def evolve(self, **changes: Any) -> None:
"""Return a new UI with 'changes' applied.
Expand Down
20 changes: 11 additions & 9 deletions pgactivity/ui.py
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,11 @@ def main(

flag = Flag.load(config, is_local=is_local, **vars(options))
ui = types.UI.make(
header=types.UIHeader(
show_instance=options.header_show_instance,
show_system=options.header_show_system,
show_workers=options.header_show_workers,
),
config=config,
flag=flag,
refresh_time=options.refresh,
Expand All @@ -48,9 +53,6 @@ def main(
wrap_query=options.wrap_query,
max_db_length=min(max(server_information.max_dbname_length, 8), 16),
filters=data.filters,
show_instance_info_in_header=options.show_instance_info_in_header,
show_worker_info_in_header=options.show_worker_info_in_header,
show_system_info_in_header=options.show_system_info_in_header,
)

key, in_help = None, False
Expand Down Expand Up @@ -97,12 +99,12 @@ def main(
elif key.name == keys.CANCEL_SELECTION:
pg_procs.reset()
ui.end_interactive()
elif keys.is_toggle_header_sys_info(key):
ui.toggle_system_info_in_header()
elif keys.is_toggle_header_inst_info(key):
ui.toggle_instance_info_in_header()
elif keys.is_toggle_header_worker_info(key):
ui.toggle_worker_info_in_header()
elif keys.is_toggle_header_system(key):
ui.header.toggle_system()
elif keys.is_toggle_header_instance(key):
ui.header.toggle_instance()
elif keys.is_toggle_header_workers(key):
ui.header.toggle_workers()
elif pg_procs.selected and key in (
keys.PROCESS_CANCEL,
keys.PROCESS_KILL,
Expand Down
6 changes: 3 additions & 3 deletions pgactivity/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -232,7 +232,7 @@ def indent(text: str) -> str:
size_ev = f"{utils.naturalsize(si.size_evolution)}/s"
uptime = utils.naturaltimedelta(si.uptime)

if ui.show_instance_info_in_header:
if ui.header.show_instance:
# First rows are always displayed, as the underlying data is always available.
columns = [
[f"* Global: {render(uptime)} uptime"],
Expand Down Expand Up @@ -268,7 +268,7 @@ def indent(text: str) -> str:
[f"{render(temp_size)} temp size"],
]
yield from render_columns(columns)
if ui.show_worker_info_in_header:
if ui.header.show_workers:
columns = [
[
f"* Worker processes: {render(si.worker_processes)}/{render(si.max_worker_processes)} total"
Expand All @@ -295,7 +295,7 @@ def indent(text: str) -> str:
yield from render_columns(columns)

# System information, only available in "local" mode.
if system_info is not None and ui.show_system_info_in_header:
if system_info is not None and ui.header.show_system:
used, bc, free, total = (
utils.naturalsize(system_info.memory.used),
utils.naturalsize(system_info.memory.buff_cached),
Expand Down
12 changes: 6 additions & 6 deletions tests/test_ui.txt
Original file line number Diff line number Diff line change
Expand Up @@ -46,9 +46,9 @@ Default CLI options, passed to ui.main():
... "rds": False,
... "username": f"{postgres.info.user}",
... "wrap_query": False,
... "show_instance_info_in_header": True,
... "show_worker_info_in_header": True,
... "show_system_info_in_header": True,
... "header_show_instance": True,
... "header_show_workers": True,
... "header_show_system": True,
... }
>>> options = argparse.Namespace(**defaults)

Expand Down Expand Up @@ -428,9 +428,9 @@ PID DATABASE USER CLIENT state Query
------------------------------------------------------------------------------------------- sending key 'q' --------------------------------------------------------------------------------------------

>>> defaults["nopid"] = True
>>> defaults["show_instance_info_in_header"] = False
>>> defaults["show_worker_info_in_header"] = False
>>> defaults["show_system_info_in_header"] = False
>>> defaults["header_show_instance"] = False
>>> defaults["header_show_workers"] = False
>>> defaults["header_show_system"] = False
>>> options = argparse.Namespace(**defaults)

One query, idle in transaction:
Expand Down
14 changes: 7 additions & 7 deletions tests/test_views.txt
Original file line number Diff line number Diff line change
Expand Up @@ -158,7 +158,7 @@ PostgreSQL 9.6 - localhost - tester@host:5432/postgres - Ref.: 10s - Duration mo
IO: 300/s max iops, 200B/s - 100/s read, 300B/s - 200/s write
Load average: 1 5 15

>>> ui.toggle_system_info_in_header()
>>> ui.header.toggle_system()
>>> header(term, ui, host=host, server_information=serverinfo,
... system_info=sysinfo, pg_version="PostgreSQL 9.6",
... width=200)
Expand All @@ -170,8 +170,8 @@ PostgreSQL 9.6 - localhost - tester@host:5432/postgres - Ref.: 10s - Duration mo
Other processes & info: 3/3 autovacuum workers, 1/10 wal senders, 0 wal receivers, 10/10 repl. slots

>>> ui = UI.make(refresh_time=10, duration_mode=DurationMode.query)
>>> ui.toggle_system_info_in_header()
>>> ui.toggle_worker_info_in_header()
>>> ui.header.toggle_system()
>>> ui.header.toggle_workers()
>>> header(term, ui, host=host, server_information=serverinfo,
... system_info=sysinfo, pg_version="PostgreSQL 9.6",
... width=200)
Expand All @@ -181,9 +181,9 @@ PostgreSQL 9.6 - localhost - tester@host:5432/postgres - Ref.: 10s - Duration mo
Activity: 15 tps, 10 insert/s, 20 update/s, 30 delete/s, 40 tuples returned/s, 5 temp files, 11.50M temp size

>>> ui = UI.make(refresh_time=2, min_duration=1.2, duration_mode=DurationMode.transaction)
>>> ui.toggle_system_info_in_header()
>>> ui.toggle_worker_info_in_header()
>>> ui.toggle_instance_info_in_header()
>>> ui.header.toggle_system()
>>> ui.header.toggle_workers()
>>> ui.header.toggle_instance()
>>> header(term, ui, host=host, server_information=serverinfo,
... system_info=sysinfo, pg_version="PostgreSQL 9.6",
... width=200)
Expand All @@ -196,7 +196,7 @@ PostgreSQL 9.6 - localhost - tester@host:5432/postgres - Ref.: 2s - Duration mod
... io_read=IOCounter(0,0),
... io_write=IOCounter(0,0),
... max_iops=0)
>>> ui.toggle_system_info_in_header()
>>> ui.header.toggle_system()
>>> header(term, ui, host=host, server_information=serverinfo,
... system_info=sysinfo, pg_version="PostgreSQL 9.6",
... width=200)
Expand Down

0 comments on commit f651a49

Please sign in to comment.