MultiSelect moved to pylib

This commit is contained in:
Dirk Alders 2025-07-25 19:52:20 +02:00
parent 0506b5f02c
commit 716ec42b48
3 changed files with 15 additions and 92 deletions

3
.gitmodules vendored
View File

@ -1,3 +1,6 @@
[submodule "report"] [submodule "report"]
path = report path = report
url = https://git.mount-mockery.de/pylib/report.git url = https://git.mount-mockery.de/pylib/report.git
[submodule "mytui"]
path = mytui
url = https://git.mount-mockery.de/pylib/mytui.git

101
loggy.py
View File

@ -10,6 +10,8 @@ from textual.app import App, ComposeResult
from textual.containers import Vertical from textual.containers import Vertical
from textual.widgets import Footer, Header, Input, RichLog, Checkbox, Select from textual.widgets import Footer, Header, Input, RichLog, Checkbox, Select
from mytui import MultiSelect
# Mapping von Log-Level-Namen zu Farben für die Anzeige # Mapping von Log-Level-Namen zu Farben für die Anzeige
LEVEL_STYLES = { LEVEL_STYLES = {
"CRITICAL": "bold white on red", "CRITICAL": "bold white on red",
@ -56,73 +58,6 @@ class LogReceiver(threading.Thread):
logging.error(f"LogReceiver-Fehler: {e}", exc_info=True) logging.error(f"LogReceiver-Fehler: {e}", exc_info=True)
class OptionSelectList(dict):
def __init__(self):
super().__init__(self)
#
self.__default_value__ = True
self.__selection_regex__ = ""
def __sorted_keys__(self):
rv = list(self.keys())
rv.sort()
return rv
def SetSelectionRegEx(self, regex: str) -> None:
self.__selection_regex__ = regex
def AddEntry(self, entry) -> None:
if entry not in self:
self[entry] = self.__default_value__
def Toggle(self, entry_num):
if entry_num < 0:
if not self.__selection_regex__:
self.__default_value__ = entry_num == -1
for key in self:
if self.__match__(key):
self[key] = entry_num == -1
elif entry_num > len(self):
raise ValueError(f"The Entry '{entry} is not in the list")
else:
entry = self.__sorted_keys__()[entry_num]
self[entry] = not self[entry]
def __match__(self, key):
try:
match = len(re.findall(self.__selection_regex__, key)) > 0
except re.error:
match = True # No valid regular expression
return match
def GetSelectList(self):
rv = []
if len(self) > 2:
rv.append(('All', -1))
rv.append(('None', -2))
for index, key in enumerate(self.__sorted_keys__()):
if self.__match__(key):
prefix = "\\[X] " if self[key] else "\\[-] "
rv.append((prefix + key, index))
return rv
def IsSelected(self, entry):
return self.get(entry, False)
class MySelect(Select):
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.__new_options__ = []
def set_options(self, options):
self.__new_options__ = options
def _on_enter(self, event):
super().set_options(self.__new_options__)
return super()._on_enter(event)
class LogViewerApp(App): class LogViewerApp(App):
"""Eine Textual-App zum Anzeigen und Filtern von Python-Logs.""" """Eine Textual-App zum Anzeigen und Filtern von Python-Logs."""
@ -137,10 +72,8 @@ class LogViewerApp(App):
super().__init__() super().__init__()
# #
self.all_logs = [] self.all_logs = []
self.__module_select_list__ = OptionSelectList() self.__module_selection__ = MultiSelect((), prompt="Module", id="module_filter")
self.__module_selection__ = MySelect((), prompt="Module", id="module_filter") self.__level_selection__ = MultiSelect((), prompt="Level", id="level_filter")
self.__level_select_list__ = OptionSelectList()
self.__level_selection__ = MySelect((), prompt="Level", id="level_filter")
self.force_critical = True self.force_critical = True
self.force_error = True self.force_error = True
self.force_warning = False self.force_warning = False
@ -167,10 +100,8 @@ class LogViewerApp(App):
def add_log(self, record: logging.LogRecord) -> None: def add_log(self, record: logging.LogRecord) -> None:
"""Fügt einen neuen Log-Eintrag hinzu und aktualisiert die Anzeige.""" """Fügt einen neuen Log-Eintrag hinzu und aktualisiert die Anzeige."""
self.__module_select_list__.AddEntry(record.name) self.__module_selection__.AddEntry(record.name)
self.__module_selection__.set_options(self.__module_select_list__.GetSelectList()) self.__level_selection__.AddEntry(record.levelname)
self.__level_select_list__.AddEntry(record.levelname)
self.__level_selection__.set_options(self.__level_select_list__.GetSelectList())
self.all_logs.append(record) self.all_logs.append(record)
if len(self.all_logs) > self.MAX_LOGS: if len(self.all_logs) > self.MAX_LOGS:
self.all_logs = self.all_logs[-self.MAX_LOGS:] self.all_logs = self.all_logs[-self.MAX_LOGS:]
@ -185,8 +116,8 @@ class LogViewerApp(App):
def _apply_filters_to_log(self, record: logging.LogRecord): def _apply_filters_to_log(self, record: logging.LogRecord):
"""Prüft einen einzelnen Log-Eintrag gegen die Filter und zeigt ihn ggf. an.""" """Prüft einen einzelnen Log-Eintrag gegen die Filter und zeigt ihn ggf. an."""
module_match = self.__module_select_list__.IsSelected(record.name) module_match = self.__module_selection__.IsSelected(record.name)
level_match = self.__level_select_list__.IsSelected(record.levelname) level_match = self.__level_selection__.IsSelected(record.levelname)
if self._force(record.levelname.lower()) or (module_match and level_match): if self._force(record.levelname.lower()) or (module_match and level_match):
level_style = LEVEL_STYLES.get(record.levelname, "white") level_style = LEVEL_STYLES.get(record.levelname, "white")
@ -226,22 +157,10 @@ class LogViewerApp(App):
def on_input_changed(self, message: Input.Changed) -> None: def on_input_changed(self, message: Input.Changed) -> None:
"""Update the tui inputs and execute task, if requireed.""" """Update the tui inputs and execute task, if requireed."""
if message.input.id == "select_filter": if message.input.id == "select_filter":
self.__module_select_list__.SetSelectionRegEx(message.value) self.__module_selection__.SetSelectionRegEx(message.value)
self.__module_selection__.set_options(self.__module_select_list__.GetSelectList())
self.__module_selection__.prompt = "Full" if not message.value else "Filtered"
def on_select_changed(self, message: Select.Changed) -> None: def on_select_changed(self, message: Select.Changed) -> None:
if message.select.id == 'module_filter': if message.select.id in ('module_filter', 'level_filter'):
if type(message.value) is int:
self.__module_select_list__.Toggle(message.value)
self.__module_selection__.clear()
self.__module_selection__.set_options(self.__module_select_list__.GetSelectList())
elif message.select.id == 'level_filter':
if type(message.value) is int:
self.__level_select_list__.Toggle(message.value)
self.__level_selection__.clear()
self.__level_selection__.set_options(self.__level_select_list__.GetSelectList())
self._update_display() self._update_display()

1
mytui Submodule

@ -0,0 +1 @@
Subproject commit bd390d27f00147c1305e244fbd6d0650a6bdcec9