ruff: apply automatic fixes

This commit is contained in:
Jörg Thalheim
2025-08-20 13:52:45 +02:00
parent 798d445f3e
commit ea2d6aab65
217 changed files with 2283 additions and 1739 deletions

View File

@@ -22,8 +22,7 @@ log = logging.getLogger(__name__)
class MainApplication(Adw.Application):
"""
This class is initialized every time the app is started
"""This class is initialized every time the app is started
Only the Adw.ApplicationWindow is a singleton.
So don't use any singletons in the Adw.Application class.
"""
@@ -78,7 +77,8 @@ class MainApplication(Adw.Application):
if "debug" in options:
ToastOverlay.use().add_toast_unique(
InfoToast("Debug logging enabled").toast, "info.debugging.enabled"
InfoToast("Debug logging enabled").toast,
"info.debugging.enabled",
)
args = command_line.get_arguments()

View File

@@ -33,8 +33,7 @@ class ClanURI:
# Check if the URI starts with clan://
# If it does, remove the clan:// prefix
prefix = "clan://"
if uri.startswith(prefix):
uri = uri[len(prefix) :]
uri = uri.removeprefix(prefix)
# Fix missing colon (caused by browsers like Firefox)
if "//" in uri and ":" not in uri.split("//", 1)[0]:

View File

@@ -14,7 +14,8 @@ log = logging.getLogger(__name__)
# Define type variables for key and value types
K = TypeVar("K") # Key type
V = TypeVar(
"V", bound=GObject.Object
"V",
bound=GObject.Object,
) # Value type, bound to GObject.GObject or its subclasses
@@ -23,8 +24,7 @@ V = TypeVar(
# clan_vm_manager/components/gkvstore.py:21: error: Definition of "install_properties" in base class "Object" is incompatible with definition in base class "GInterface" [misc]
# clan_vm_manager/components/gkvstore.py:21: error: Definition of "getv" in base class "Object" is incompatible with definition in base class "GInterface" [misc]
class GKVStore[K, V: GObject.Object](GObject.GObject, Gio.ListModel): # type: ignore[misc]
"""
A simple key-value store that implements the Gio.ListModel interface, with generic types for keys and values.
"""A simple key-value store that implements the Gio.ListModel interface, with generic types for keys and values.
Only use self[key] and del self[key] for accessing the items for better performance.
This class could be optimized by having the objects remember their position in the list.
"""
@@ -57,7 +57,9 @@ class GKVStore[K, V: GObject.Object](GObject.GObject, Gio.ListModel): # type: i
return False, -1
def find_with_equal_func(
self, item: V, equal_func: Callable[[V, V], bool]
self,
item: V,
equal_func: Callable[[V, V], bool],
) -> tuple[bool, int]:
log.warning("Finding is O(n) in GKVStore. Better use indexing")
for i, v in enumerate(self.values()):
@@ -66,7 +68,10 @@ class GKVStore[K, V: GObject.Object](GObject.GObject, Gio.ListModel): # type: i
return False, -1
def find_with_equal_func_full(
self, item: V, equal_func: Callable[[V, V, Any], bool], user_data: Any
self,
item: V,
equal_func: Callable[[V, V, Any], bool],
user_data: Any,
) -> tuple[bool, int]:
log.warning("Finding is O(n) in GKVStore. Better use indexing")
for i, v in enumerate(self.values()):
@@ -77,7 +82,7 @@ class GKVStore[K, V: GObject.Object](GObject.GObject, Gio.ListModel): # type: i
def insert(self, position: int, item: V) -> None:
log.warning("Inserting is O(n) in GKVStore. Better use append")
log.warning(
"This functions may have incorrect items_changed signal behavior. Please test it"
"This functions may have incorrect items_changed signal behavior. Please test it",
)
key = self.key_gen(item)
if key in self._items:
@@ -105,7 +110,10 @@ class GKVStore[K, V: GObject.Object](GObject.GObject, Gio.ListModel): # type: i
self.items_changed(position, 0, 1)
def insert_sorted(
self, item: V, compare_func: Callable[[V, V, Any], int], user_data: Any
self,
item: V,
compare_func: Callable[[V, V, Any], int],
user_data: Any,
) -> None:
msg = "insert_sorted is not implemented in GKVStore"
raise NotImplementedError(msg)
@@ -225,6 +233,7 @@ class GKVStore[K, V: GObject.Object](GObject.GObject, Gio.ListModel): # type: i
return self.values()[-1]
def register_on_change(
self, callback: Callable[["GKVStore[K,V]", int, int, int], None]
self,
callback: Callable[["GKVStore[K,V]", int, int, int], None],
) -> None:
self.connect("items-changed", callback)

View File

@@ -67,8 +67,7 @@ class EmptySplash(Gtk.Box):
return pixbuf
def _on_join(self, button: Gtk.Button, entry: Gtk.Entry) -> None:
"""
Callback for the join button
"""Callback for the join button
Extracts the text from the entry and calls the on_join callback
"""
log.info(f"Splash screen: Joining {entry.get_text()}")

View File

@@ -128,7 +128,6 @@ def encode_path(path: str, prefix: bool = True) -> bytes:
On Windows, also append prefix to enable extended-length path.
"""
if sys.platform == "win32" and prefix:
path = path.replace("/", "\\")
@@ -142,10 +141,12 @@ def encode_path(path: str, prefix: bool = True) -> bytes:
# from pynicotine.utils import truncate_string_byte
def truncate_string_byte(
string: str, byte_limit: int, encoding: str = "utf-8", ellipsize: bool = False
string: str,
byte_limit: int,
encoding: str = "utf-8",
ellipsize: bool = False,
) -> str:
"""Truncates a string to fit inside a byte limit."""
string_bytes = string.encode(encoding)
if len(string_bytes) <= byte_limit:
@@ -217,7 +218,8 @@ class BaseImplementation:
def create_menu(self) -> None:
self.show_hide_item = self.create_item(
"default", self.application.on_window_hide_unhide
"default",
self.application.on_window_hide_unhide,
)
# self.create_item()
@@ -365,17 +367,26 @@ class StatusNotifierImplementation(BaseImplementation):
def add_property(self, name: str, signature: Any, value: Any) -> None:
self.properties[name] = StatusNotifierImplementation.DBusProperty(
name, signature, value
name,
signature,
value,
)
def add_signal(self, name: str, args: Any) -> None:
self.signals[name] = StatusNotifierImplementation.DBusSignal(name, args)
def add_method(
self, name: str, in_args: Any, out_args: Any, callback: Any
self,
name: str,
in_args: Any,
out_args: Any,
callback: Any,
) -> None:
self.methods[name] = StatusNotifierImplementation.DBusMethod(
name, in_args, out_args, callback
name,
in_args,
out_args,
callback,
)
def emit_signal(self, name: str, *args: Any) -> None:
@@ -411,7 +422,12 @@ class StatusNotifierImplementation(BaseImplementation):
invocation.return_value(return_value)
def on_get_property(
self, _connection, _sender, _path, _interface_name, property_name
self,
_connection,
_sender,
_path,
_interface_name,
property_name,
):
prop = self.properties[property_name]
return GLib.Variant(prop.signature, prop.value)
@@ -483,7 +499,8 @@ class StatusNotifierImplementation(BaseImplementation):
for idx, item in self._items.items():
serialized_item = GLib.Variant(
"(ia{sv}av)", (idx, self._serialize_item(item), [])
"(ia{sv}av)",
(idx, self._serialize_item(item), []),
)
serialized_items.append(serialized_item)
@@ -558,7 +575,7 @@ class StatusNotifierImplementation(BaseImplementation):
try:
self.bus = Gio.bus_get_sync(bus_type=Gio.BusType.SESSION)
self.tray_icon = self.StatusNotifierItemService(
activate_callback=self.activate_callback
activate_callback=self.activate_callback,
)
self.tray_icon.register()
@@ -573,7 +590,8 @@ class StatusNotifierImplementation(BaseImplementation):
interface_name="org.kde.StatusNotifierWatcher",
method_name="RegisterStatusNotifierItem",
parameters=GLib.Variant(
"(s)", ("/org/ayatana/NotificationItem/Nicotine",)
"(s)",
("/org/ayatana/NotificationItem/Nicotine",),
),
reply_type=None,
flags=Gio.DBusCallFlags.NONE,
@@ -590,7 +608,6 @@ class StatusNotifierImplementation(BaseImplementation):
@staticmethod
def check_icon_path(icon_name, icon_path) -> bool:
"""Check if tray icons exist in the specified icon path."""
if not icon_path:
return False
@@ -600,7 +617,8 @@ class StatusNotifierImplementation(BaseImplementation):
with os.scandir(encode_path(icon_path)) as entries:
for entry in entries:
if entry.is_file() and entry.name.decode(
"utf-8", "replace"
"utf-8",
"replace",
).startswith(icon_scheme):
return True
@@ -611,8 +629,8 @@ class StatusNotifierImplementation(BaseImplementation):
def get_icon_path(self):
"""Returns an icon path to use for tray icons, or None to fall back to
system-wide icons."""
system-wide icons.
"""
# icon_path = self.application.get_application_icon_path()
return ""
@@ -811,7 +829,8 @@ class Win32Implementation(BaseImplementation):
from ctypes import windll
windll.user32.UnregisterClassW(
self.WINDOW_CLASS_NAME, self._window_class.h_instance
self.WINDOW_CLASS_NAME,
self._window_class.h_instance,
)
self._window_class = None
@@ -850,7 +869,12 @@ class Win32Implementation(BaseImplementation):
if GTK_API_VERSION >= 4:
icon = ICON_THEME.lookup_icon(
icon_name, fallbacks=None, size=icon_size, scale=1, direction=0, flags=0
icon_name,
fallbacks=None,
size=icon_size,
scale=1,
direction=0,
flags=0,
)
icon_path = icon.get_file().get_path()
@@ -858,7 +882,9 @@ class Win32Implementation(BaseImplementation):
return ico_buffer
pixbuf = GdkPixbuf.Pixbuf.new_from_file_at_size(
icon_path, icon_size, icon_size
icon_path,
icon_size,
icon_size,
)
else:
icon = ICON_THEME.lookup_icon(icon_name, size=icon_size, flags=0)
@@ -931,7 +957,8 @@ class Win32Implementation(BaseImplementation):
),
u_callback_message=self.WM_TRAYICON,
sz_tip=truncate_string_byte(
pynicotine.__application_name__, byte_limit=127
pynicotine.__application_name__,
byte_limit=127,
),
)
action = self.NIM_ADD
@@ -943,10 +970,14 @@ class Win32Implementation(BaseImplementation):
self._notify_id.h_icon = self._h_icon
self._notify_id.sz_info_title = truncate_string_byte(
title, byte_limit=63, ellipsize=True
title,
byte_limit=63,
ellipsize=True,
)
self._notify_id.sz_info = truncate_string_byte(
message, byte_limit=255, ellipsize=True
message,
byte_limit=255,
ellipsize=True,
)
windll.shell32.Shell_NotifyIconW(action, byref(self._notify_id))
@@ -1019,10 +1050,16 @@ class Win32Implementation(BaseImplementation):
item_info = self._serialize_menu_item(item)
if not windll.user32.SetMenuItemInfoW(
self._menu, item_id, False, byref(item_info)
self._menu,
item_id,
False,
byref(item_info),
):
windll.user32.InsertMenuItemW(
self._menu, item_id, False, byref(item_info)
self._menu,
item_id,
False,
byref(item_info),
)
def set_icon(self, icon_name):

View File

@@ -56,10 +56,14 @@ class VMObject(GObject.Object):
# Create a process object to store the VM process
self.vm_process: MPProcess = MPProcess(
"vm_dummy", mp.Process(), Path("./dummy")
"vm_dummy",
mp.Process(),
Path("./dummy"),
)
self.build_process: MPProcess = MPProcess(
"build_dummy", mp.Process(), Path("./dummy")
"build_dummy",
mp.Process(),
Path("./dummy"),
)
self._start_thread: threading.Thread = threading.Thread()
self.machine: Machine | None = None
@@ -77,7 +81,8 @@ class VMObject(GObject.Object):
# Create a temporary directory to store the logs
self.log_dir: tempfile.TemporaryDirectory = tempfile.TemporaryDirectory(
prefix="clan_vm-", suffix=f"-{self.data.flake.flake_attr}"
prefix="clan_vm-",
suffix=f"-{self.data.flake.flake_attr}",
)
self._logs_id: int = 0
self._log_file: IO[str] | None = None
@@ -87,7 +92,8 @@ class VMObject(GObject.Object):
# and block the signal while we change the state. This is cursed.
self.switch: Gtk.Switch = Gtk.Switch()
self.switch_handler_id: int = self.switch.connect(
"notify::active", self._on_switch_toggle
"notify::active",
self._on_switch_toggle,
)
self.connect("vm_status_changed", self._on_vm_status_changed)
@@ -145,7 +151,8 @@ class VMObject(GObject.Object):
@contextmanager
def _create_machine(self) -> Generator[Machine]:
uri = ClanURI.from_str(
url=str(self.data.flake.flake_url), machine_name=self.data.flake.flake_attr
url=str(self.data.flake.flake_url),
machine_name=self.data.flake.flake_attr,
)
self.machine = Machine(
name=self.data.flake.flake_attr,
@@ -154,7 +161,8 @@ class VMObject(GObject.Object):
assert self.machine is not None
state_dir = vm_state_dir(
flake_url=self.machine.flake.identifier, vm_name=self.machine.name
flake_url=self.machine.flake.identifier,
vm_name=self.machine.name,
)
self.qmp_wrap = QMPWrapper(state_dir)
assert self.machine is not None
@@ -194,7 +202,9 @@ class VMObject(GObject.Object):
self.switch.set_sensitive(True)
# Start the logs watcher
self._logs_id = GLib.timeout_add(
50, self._get_logs_task, self.build_process
50,
self._get_logs_task,
self.build_process,
)
if self._logs_id == 0:
log.error("Failed to start VM log watcher")
@@ -307,7 +317,7 @@ class VMObject(GObject.Object):
diff = datetime.datetime.now(tz=datetime.UTC) - start_time
if diff.seconds > self.KILL_TIMEOUT:
log.error(
f"VM {self.get_id()} has not stopped after {self.KILL_TIMEOUT}s. Killing it"
f"VM {self.get_id()} has not stopped after {self.KILL_TIMEOUT}s. Killing it",
)
self.vm_process.kill_group()
break
@@ -334,7 +344,8 @@ class VMObject(GObject.Object):
log.debug(f"VM {self.get_id()} has stopped")
ToastOverlay.use().add_toast_unique(
InfoToast(f"Stopped {self.get_id()}").toast, "info.vm.exit"
InfoToast(f"Stopped {self.get_id()}").toast,
"info.vm.exit",
)
def shutdown(self) -> None:

View File

@@ -92,7 +92,9 @@ def add_history(uri: ClanURI) -> HistoryEntry:
def _add_maschine_to_history_list(
uri_path: str, uri_machine: str, entries: list[HistoryEntry]
uri_path: str,
uri_machine: str,
entries: list[HistoryEntry],
) -> HistoryEntry:
for new_entry in entries:
if (
@@ -143,10 +145,16 @@ def parse_args() -> argparse.Namespace:
)
add_parser = subparser.add_parser("add", help="Add a clan flake")
add_parser.add_argument(
"uri", type=ClanURI.from_str, help="Path to the flake", default="."
"uri",
type=ClanURI.from_str,
help="Path to the flake",
default=".",
)
add_parser.add_argument(
"--all", help="Add all machines", default=False, action="store_true"
"--all",
help="Add all machines",
default=False,
action="store_true",
)
add_parser.set_defaults(func=add_history_command)
list_parser = subparser.add_parser("list", help="List recently used flakes")

View File

@@ -16,8 +16,7 @@ log = logging.getLogger(__name__)
class ToastOverlay:
"""
The ToastOverlay is a class that manages the display of toasts
"""The ToastOverlay is a class that manages the display of toasts
It should be used as a singleton in your application to prevent duplicate toasts
Usage
"""
@@ -53,11 +52,14 @@ class ErrorToast:
toast: Adw.Toast
def __init__(
self, message: str, persistent: bool = False, details: str = ""
self,
message: str,
persistent: bool = False,
details: str = "",
) -> None:
super().__init__()
self.toast = Adw.Toast.new(
f"""<span foreground='red'>❌ Error </span> {message}"""
f"""<span foreground='red'>❌ Error </span> {message}""",
)
self.toast.set_use_markup(True)
@@ -85,7 +87,7 @@ class WarningToast:
def __init__(self, message: str, persistent: bool = False) -> None:
super().__init__()
self.toast = Adw.Toast.new(
f"<span foreground='orange'>⚠ Warning </span> {message}"
f"<span foreground='orange'>⚠ Warning </span> {message}",
)
self.toast.set_use_markup(True)
@@ -135,7 +137,7 @@ class LogToast:
) -> None:
super().__init__()
self.toast = Adw.Toast.new(
f"""Logs are available <span weight="regular">{message}</span>"""
f"""Logs are available <span weight="regular">{message}</span>""",
)
self.toast.set_use_markup(True)

View File

@@ -45,8 +45,7 @@ class JoinValue(GObject.Object):
class JoinList:
"""
This is a singleton.
"""This is a singleton.
It is initialized with the first call of use()
"""
@@ -69,28 +68,32 @@ class JoinList:
return cls._instance
def rerender_join_list(
self, source: GKVStore, position: int, removed: int, added: int
self,
source: GKVStore,
position: int,
removed: int,
added: int,
) -> None:
self.list_store.items_changed(
0, self.list_store.get_n_items(), self.list_store.get_n_items()
0,
self.list_store.get_n_items(),
self.list_store.get_n_items(),
)
def is_empty(self) -> bool:
return self.list_store.get_n_items() == 0
def push(self, uri: ClanURI, after_join: Callable[[JoinValue], None]) -> None:
"""
Add a join request.
"""Add a join request.
This method can add multiple join requests if called subsequently for each request.
"""
value = JoinValue(uri)
machine_id = Machine(uri.machine_name, uri.flake)
machine_id_list = []
for machine_obj in self.list_store:
mvalue: ClanURI = cast(JoinValue, machine_obj).url
mvalue: ClanURI = cast("JoinValue", machine_obj).url
machine = Machine(mvalue.machine_name, mvalue.flake)
machine_id_list.append(machine.get_id())

View File

@@ -8,8 +8,7 @@ from gi.repository import Adw
class ViewStack:
"""
This is a singleton.
"""This is a singleton.
It is initialized with the first call of use()
Usage:

View File

@@ -53,7 +53,8 @@ class ClanStore:
if cls._instance is None:
cls._instance = cls.__new__(cls)
cls._clan_store = GKVStore(
VMStore, lambda store: store.first().data.flake.flake_url
VMStore,
lambda store: store.first().data.flake.flake_url,
)
cls._emitter = Emitter()
@@ -74,19 +75,24 @@ class ClanStore:
return self._logging_vm
def register_on_deep_change(
self, callback: Callable[[GKVStore, int, int, int], None]
self,
callback: Callable[[GKVStore, int, int, int], None],
) -> None:
"""
Register a callback that is called when a clan_store or one of the included VMStores changes
"""
"""Register a callback that is called when a clan_store or one of the included VMStores changes"""
def on_vmstore_change(
store: VMStore, position: int, removed: int, added: int
store: VMStore,
position: int,
removed: int,
added: int,
) -> None:
callback(store, position, removed, added)
def on_clanstore_change(
store: "GKVStore", position: int, removed: int, added: int
store: "GKVStore",
position: int,
removed: int,
added: int,
) -> None:
if added > 0:
store.values()[position].register_on_change(on_vmstore_change)
@@ -120,7 +126,9 @@ class ClanStore:
logs_view: Logs = views.get_child_by_name("logs") # type: ignore
def file_read_callback(
source_object: Gio.File, result: Gio.AsyncResult, _user_data: Any
source_object: Gio.File,
result: Gio.AsyncResult,
_user_data: Any,
) -> None:
try:
# Finish the asynchronous read operation
@@ -155,7 +163,7 @@ class ClanStore:
if old_vm:
log.info(
f"VM {vm.data.flake.flake_attr} already exists in store. Updating data field."
f"VM {vm.data.flake.flake_attr} already exists in store. Updating data field.",
)
old_vm.update(vm.data)
else:

View File

@@ -13,7 +13,8 @@ ListItem = TypeVar("ListItem", bound=GObject.Object)
def create_details_list[ListItem: GObject.Object](
model: Gio.ListStore, render_row: Callable[[Gtk.ListBox, ListItem], Gtk.Widget]
model: Gio.ListStore,
render_row: Callable[[Gtk.ListBox, ListItem], Gtk.Widget],
) -> Gtk.ListBox:
boxed_list = Gtk.ListBox()
boxed_list.set_selection_mode(Gtk.SelectionMode.NONE)
@@ -28,7 +29,10 @@ class PreferencesValue(GObject.Object):
data: Any
def __init__(
self, variant: Literal["CPU", "MEMORY"], editable: bool, data: Any
self,
variant: Literal["CPU", "MEMORY"],
editable: bool,
data: Any,
) -> None:
super().__init__()
self.variant = variant
@@ -44,13 +48,16 @@ class Details(Gtk.Box):
preferences_store.append(PreferencesValue("CPU", True, 1))
self.details_list = create_details_list(
model=preferences_store, render_row=self.render_entry_row
model=preferences_store,
render_row=self.render_entry_row,
)
self.append(self.details_list)
def render_entry_row(
self, boxed_list: Gtk.ListBox, item: PreferencesValue
self,
boxed_list: Gtk.ListBox,
item: PreferencesValue,
) -> Gtk.Widget:
cores: int | None = os.cpu_count()
fcores = float(cores) if cores else 1.0

View File

@@ -46,8 +46,7 @@ def create_boxed_list[CustomStore: Gio.ListModel, ListItem: GObject.Object](
class ClanList(Gtk.Box):
"""
The ClanList
"""The ClanList
Is the composition of
the ClanListToolbar
the clanListView
@@ -70,7 +69,8 @@ class ClanList(Gtk.Box):
# Add join list
self.join_boxed_list = create_boxed_list(
model=JoinList.use().list_store, render_row=self.render_join_row
model=JoinList.use().list_store,
render_row=self.render_join_row,
)
self.join_boxed_list.add_css_class("join-list")
self.append(self.join_boxed_list)
@@ -79,7 +79,8 @@ class ClanList(Gtk.Box):
clan_store.connect("is_ready", self.display_splash)
self.group_list = create_boxed_list(
model=clan_store.clan_store, render_row=self.render_group_row
model=clan_store.clan_store,
render_row=self.render_group_row,
)
self.group_list.add_css_class("group-list")
self.append(self.group_list)
@@ -95,7 +96,9 @@ class ClanList(Gtk.Box):
self.append(self.splash)
def render_group_row(
self, boxed_list: Gtk.ListBox, vm_store: VMStore
self,
boxed_list: Gtk.ListBox,
vm_store: VMStore,
) -> Gtk.Widget:
self.remove(self.splash)
@@ -199,7 +202,8 @@ class ClanList(Gtk.Box):
action_id = base64.b64encode(vm.get_id().encode("utf-8")).decode("utf-8")
build_logs_action = Gio.SimpleAction.new(
f"logs.{action_id}", GLib.VariantType.new("s")
f"logs.{action_id}",
GLib.VariantType.new("s"),
)
build_logs_action.connect("activate", self.on_show_build_logs)
@@ -213,7 +217,9 @@ class ClanList(Gtk.Box):
# set a callback function for conditionally enabling the build_logs action
def on_vm_build_notify(
vm: VMObject, is_building: bool, is_running: bool
vm: VMObject,
is_building: bool,
is_running: bool,
) -> None:
build_logs_action.set_enabled(is_building or is_running)
app.add_action(build_logs_action)
@@ -279,7 +285,9 @@ class ClanList(Gtk.Box):
views.set_visible_child_name("logs")
def render_join_row(
self, boxed_list: Gtk.ListBox, join_val: JoinValue
self,
boxed_list: Gtk.ListBox,
join_val: JoinValue,
) -> Gtk.Widget:
if boxed_list.has_css_class("no-shadow"):
boxed_list.remove_css_class("no-shadow")
@@ -300,13 +308,13 @@ class ClanList(Gtk.Box):
ToastOverlay.use().add_toast_unique(
WarningToast(
f"""<span weight="regular">{join_val.url.machine_name!s}</span> Already exists. Joining again will update it"""
f"""<span weight="regular">{join_val.url.machine_name!s}</span> Already exists. Joining again will update it""",
).toast,
"warning.duplicate.join",
)
row.set_subtitle(
sub + "\nClan already exists. Joining again will update it"
sub + "\nClan already exists. Joining again will update it",
)
avatar = Adw.Avatar()

View File

@@ -11,8 +11,7 @@ log = logging.getLogger(__name__)
class Logs(Gtk.Box):
"""
Simple log view
"""Simple log view
This includes a banner and a text view and a button to close the log and navigate back to the overview
"""
@@ -44,9 +43,7 @@ class Logs(Gtk.Box):
self.banner.set_title(title)
def set_message(self, message: str) -> None:
"""
Set the log message. This will delete any previous message
"""
"""Set the log message. This will delete any previous message"""
buffer = self.text_view.get_buffer()
buffer.set_text(message)
@@ -54,9 +51,7 @@ class Logs(Gtk.Box):
self.text_view.scroll_to_mark(mark, 0.05, True, 0.0, 1.0)
def append_message(self, message: str) -> None:
"""
Append to the end of a potentially existent log message
"""
"""Append to the end of a potentially existent log message"""
buffer = self.text_view.get_buffer()
end_iter = buffer.get_end_iter()
buffer.insert(end_iter, message) # type: ignore