From 2f6100dd4bb05e52e7a720c198424087d4d39afc Mon Sep 17 00:00:00 2001 From: Sandu Bogdan Date: Mon, 8 Dec 2025 16:10:16 +0200 Subject: [PATCH 1/5] Enhanced Logic (WIP) --- pyproject.toml | 2 +- src/core/bar_helper.py | 20 ++++++++++--------- src/main.py | 44 +++++++++++++++++++++++++++++++++++++++++- 3 files changed, 55 insertions(+), 11 deletions(-) diff --git a/pyproject.toml b/pyproject.toml index 1c58e73ec..d8c4b80cc 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -11,7 +11,7 @@ authors = [ ] license = "MIT" readme = "README.md" -requires-python = ">= 3.14" +requires-python = ">= 3.13" dependencies = [ "pyqt6==6.10.0", "cerberus", diff --git a/src/core/bar_helper.py b/src/core/bar_helper.py index 08d1e2c0f..d5f82f05a 100644 --- a/src/core/bar_helper.py +++ b/src/core/bar_helper.py @@ -27,6 +27,8 @@ from core.utils.win32.constants import DWMWA_CLOAKED, S_OK from core.utils.win32.utilities import apply_qmenu_style, get_monitor_hwnd, get_window_rect +import log as _log + class AutoHideZone(QFrame): """A transparent zone at the edge of the screen to detect when to show the bar""" @@ -220,14 +222,14 @@ def start_monitoring(self): try: self._timer.start() except Exception as e: - logging.error(f"Failed to start fullscreen polling: {e}") + _log.log_error("Failed to start fullscreen polling", e) def stop_monitoring(self): """Stop monitoring for fullscreen applications""" try: self._timer.stop() except Exception as e: - logging.error(f"Failed to stop fullscreen polling: {e}") + _log.log_error("Failed to stop fullscreen polling", e) def is_window_cloaked(self, hwnd): """Check if a window is cloaked (hidden by DWM)""" @@ -518,7 +520,7 @@ def _on_menu_about_to_hide(self): self.parent._autohide_manager._hide_timer.start(self.parent._autohide_manager._autohide_delay) except Exception as e: - logging.error(f"Failed to restart autohide timer: {e}") + _log.log_error("Failed to restart autohide timer", e) def _populate_widgets_menu(self, widgets_menu): if not any(self._widgets.get(layout) for layout in ["left", "center", "right"]): @@ -593,7 +595,7 @@ def controlled_hide(): widget.hide = controlled_hide except Exception as e: - logging.error(f"Failed to toggle widget {self._get_widget_display_name(widget)}: {e}") + _log.log_error(f"Failed to toggle widget {self._get_widget_display_name(widget)}", e) def _get_widget_display_name(self, widget): for layout_type, widget_list in self._widgets.items(): @@ -613,7 +615,7 @@ def _open_task_manager(self): try: subprocess.Popen("taskmgr", shell=True, creationflags=subprocess.CREATE_NO_WINDOW) except Exception as e: - logging.error(f"Failed to open Task Manager: {e}") + _log.log_error("Failed to open Task Manager", e) def _take_screenshot(self): """Take a screenshot of the bar with proper padding""" @@ -669,7 +671,7 @@ def _take_screenshot(self): self._screenshot_flash() except Exception as e: - logging.error(f"Failed to take screenshot: {e}") + _log.log_error("Failed to take screenshot", e) def _screenshot_flash(self): """Create a flashing effect on the bar when taking screenshot""" @@ -688,7 +690,7 @@ def _screenshot_flash(self): self.flash_animation.start() except Exception as e: - logging.error(f"Failed to create flash effect: {e}") + _log.log_error("Failed to create flash effect", e) def _enable_autohide(self): """Enable autohide functionality for the bar""" @@ -702,7 +704,7 @@ def _enable_autohide(self): self.parent._autohide_manager.setup_autohide() except Exception as e: - logging.error(f"Failed to enable autohide: {e}") + _log.log_error("Failed to enable autohide", e) def _disable_autohide(self): """Disable autohide functionality""" @@ -716,4 +718,4 @@ def _disable_autohide(self): self.parent.show() except Exception as e: - logging.error(f"Failed to disable autohide: {e}") + _log.log_error("Failed to disable autohide", e) diff --git a/src/main.py b/src/main.py index 54326af94..1e75e0cf0 100644 --- a/src/main.py +++ b/src/main.py @@ -5,6 +5,29 @@ import sys import time from sys import argv +import win32api +import winreg + +def get_windows_version(): + # Read core OS information from the registry + key = winreg.OpenKey( + winreg.HKEY_LOCAL_MACHINE, + r"SOFTWARE\Microsoft\Windows NT\CurrentVersion" + ) + + product_name = winreg.QueryValueEx(key, "ProductName")[0] + current_build = winreg.QueryValueEx(key, "CurrentBuild")[0] + ubr = winreg.QueryValueEx(key, "UBR")[0] + + # Construct full build string + full_build = f"{current_build}.{ubr}" + + # Correct Windows version label if necessary + major_build = int(current_build) + if major_build >= 22000 and not product_name.startswith("Windows 11"): + product_name = product_name.replace("Windows 10", "Windows 11") + + return f"{product_name}, Build {full_build}" import qasync from PyQt6.QtWidgets import QApplication @@ -20,6 +43,8 @@ from core.watcher import create_observer from env_loader import load_env, set_font_engine +import log as _log + @contextlib.contextmanager def single_instance_lock(name="yasb_reborn"): @@ -86,6 +111,23 @@ def single_instance_lock(name="yasb_reborn"): def main(): + logging.debug("main() entrypoint reached.") + + try: + data = get_windows_version() + logging.info("Retrieved OS information.") + logging.info(f" | {data}") + except BaseException as e: + logging.info("Failed to retrieve OS information.") + logging.info(f" | {e}") + try: + platform = __import__("platform") + simple_windows_version = lambda: f"Windows {platform.release()}, Build {platform.version()}" + logging.info("Retrieved minimal OS information (may be innacurate).") + logging.info(f" | {simple_windows_version}") + except BaseException as e: + logging.warning("Failed to retrieve OS information.") + # Application instance should be created first app = QApplication(argv) app.setQuitOnLastWindowClosed(False) @@ -129,7 +171,7 @@ def stop_observer(): if update_service.is_update_supported(): start_update_checker() except Exception as e: - logging.error(f"Failed to start auto update service: {e}") + _log.log_error(f"Failed to start auto update service", e) with loop: loop.run_forever() From 17e2cfd763cf6d9cecbdc530104ed3813a0e26aa Mon Sep 17 00:00:00 2001 From: Sandu Bogdan Date: Mon, 8 Dec 2025 18:13:12 +0200 Subject: [PATCH 2/5] Logging improvements --- src/core/bar.py | 6 ++++-- src/core/bar_helper.py | 4 ++-- src/core/bar_manager.py | 3 ++- src/core/config.py | 6 ++++-- src/core/tray.py | 12 +++++++----- src/core/utils/controller.py | 3 ++- src/core/utils/css_processor.py | 3 ++- src/core/utils/update_service.py | 6 ++++-- src/core/utils/widget_builder.py | 2 ++ src/core/utils/win32/app_icons.py | 6 ++++-- src/core/utils/win32/utilities.py | 10 ++++++---- src/core/utils/win32/window_actions.py | 8 +++++--- src/main.py | 10 ++++++++-- 13 files changed, 52 insertions(+), 27 deletions(-) diff --git a/src/core/bar.py b/src/core/bar.py index 1b29bce6a..b372cc117 100644 --- a/src/core/bar.py +++ b/src/core/bar.py @@ -14,6 +14,8 @@ from core.validation.bar import BAR_DEFAULTS from settings import APP_BAR_TITLE +import pretty_log as _log + try: from core.utils.win32 import app_bar @@ -96,7 +98,7 @@ def __init__( self._os_theme_manager = OsThemeManager(self._bar_frame, self) self._os_theme_manager.update_theme_class() except Exception as e: - logging.error(f"Failed to initialize theme manager: {e}") + _log.log_error("Failed to initialize theme manager", e) self._os_theme_manager = None # Initialize fullscreen manager @@ -104,7 +106,7 @@ def __init__( try: self._fullscreen_manager = FullscreenManager(self, self) except Exception as e: - logging.error(f"Failed to initialize fullscreen manager: {e}") + _log.log_error("Failed to initialize fullscreen manager", e) self._fullscreen_manager = None self.position_bar(init) diff --git a/src/core/bar_helper.py b/src/core/bar_helper.py index d5f82f05a..1b6c50c1d 100644 --- a/src/core/bar_helper.py +++ b/src/core/bar_helper.py @@ -27,7 +27,7 @@ from core.utils.win32.constants import DWMWA_CLOAKED, S_OK from core.utils.win32.utilities import apply_qmenu_style, get_monitor_hwnd, get_window_rect -import log as _log +import pretty_log as _log class AutoHideZone(QFrame): @@ -419,7 +419,7 @@ def detect_os_theme(self) -> bool: value, _ = winreg.QueryValueEx(key, "AppsUseLightTheme") return value == 0 except Exception as e: - logging.error(f"Failed to determine Windows theme: {e}") + _log.log_error(f"Failed to determine Windows theme", e) return False def update_theme_class(self): diff --git a/src/core/bar_manager.py b/src/core/bar_manager.py index 22b463a84..7ce0f645e 100644 --- a/src/core/bar_manager.py +++ b/src/core/bar_manager.py @@ -15,6 +15,7 @@ from core.utils.utilities import get_screen_by_name from core.utils.widget_builder import WidgetBuilder +import pretty_log as _log class BarManager(QObject): styles_modified = pyqtSignal() @@ -53,7 +54,7 @@ def on_config_modified(self): try: config = get_config(show_error_dialog=True) except Exception as e: - logging.error(f"Error loading config: {e}") + _log.log_error(f"Error loading config", e) return if config and (config != self.config): if any( diff --git a/src/core/config.py b/src/core/config.py index 7e93f3a3f..1f61c66be 100644 --- a/src/core/config.py +++ b/src/core/config.py @@ -18,6 +18,8 @@ from core.utils.css_processor import CSSProcessor from core.validation.config import CONFIG_SCHEMA +import pretty_log as _log + SRC_CONFIGURATION_DIR = os.path.dirname(sys.executable) if getattr(sys, "frozen", False) else os.path.dirname(argv[0]) HOME_CONFIGURATION_DIR = path.join(Path.home(), settings.DEFAULT_CONFIG_DIRECTORY) HOME_STYLES_PATH = path.normpath(path.join(HOME_CONFIGURATION_DIR, settings.DEFAULT_STYLES_FILENAME)) @@ -121,7 +123,7 @@ def get_config(show_error_dialog=False) -> Union[dict, None]: additional_details=pretty_errors, ) except ParserError as e: - logging.error(f"The file '{config_path}' contains Parser Error(s). Please fix:\n{str(e)}") + _log.log_error(f"The file '{config_path}' contains Parser Error(s). Please fix", e) except FileNotFoundError: logging.error(f"The file '{config_path}' could not be found. Does it exist?") except OSError: @@ -136,7 +138,7 @@ def get_stylesheet(show_error_dialog=False) -> Union[str, None]: return css_content except SyntaxErr as e: - logging.error(f"The file '{styles_path}' contains Syntax Error(s). Please fix:\n{str(e)}") + _log.log_error(f"The file '{styles_path}' contains Syntax Error(s). Please fix:", e) if show_error_dialog: raise_info_alert( title="Failed to load recently updated stylesheet file.", diff --git a/src/core/tray.py b/src/core/tray.py index bde74bb62..791d25d5f 100644 --- a/src/core/tray.py +++ b/src/core/tray.py @@ -22,6 +22,8 @@ SCRIPT_PATH, ) +import pretty_log as _log + VBS_PATH = os.path.join(SCRIPT_PATH, "yasb.vbs") EXE_PATH = os.path.join(SCRIPT_PATH, "yasb.exe") THEME_EXE_PATH = os.path.join(SCRIPT_PATH, "yasb_themes.exe") @@ -61,7 +63,7 @@ def _load_config(self): try: config = get_config(show_error_dialog=True) except Exception as e: - logging.error(f"Error loading config: {e}") + _log.log_error(f"Error loading config", e) return if config["komorebi"]: self.komorebi_start = config["komorebi"]["start_command"] @@ -205,7 +207,7 @@ def is_wm_installed(self, wm) -> bool: wm_path = shutil.which(wm) return wm_path is not None except Exception as e: - logging.error(f"Error checking {wm} installation: {e}") + _log.log_error(f"Error checking {wm} installation", e) return False def _enable_startup(self): @@ -224,7 +226,7 @@ def _open_config(self): try: subprocess.run(["explorer", str(os.path.join(Path.home(), DEFAULT_CONFIG_DIRECTORY))]) except Exception as e: - logging.error(f"Failed to open config directory: {e}") + _log.log_error("Failed to open config directory", e) def _run_wm_command(self, wm, command): def wm_command(): @@ -237,7 +239,7 @@ def wm_command(): creationflags=subprocess.CREATE_NO_WINDOW, ) except Exception as e: - logging.error(f"Failed to start {wm}: {e}") + _log.log_error(f"Failed to start {wm}", e) threading.Thread(target=wm_command).start() @@ -251,7 +253,7 @@ def _open_in_browser(self, url): try: webbrowser.open(url) except Exception as e: - logging.error(f"Failed to open browser: {e}") + _log.log_error(f"Failed to open browser", e) def _show_about_dialog(self): dialog = AboutDialog(self) diff --git a/src/core/utils/controller.py b/src/core/utils/controller.py index 850aa8f05..01c4c1e4a 100644 --- a/src/core/utils/controller.py +++ b/src/core/utils/controller.py @@ -9,6 +9,7 @@ from core.utils.cli_server import CliPipeHandler from core.utils.win32.utilities import find_focused_screen +import pretty_log as _log def reload_application(msg="Reloading Application..."): try: @@ -27,7 +28,7 @@ def reload_application(msg="Reloading Application..."): if app is not None: QMetaObject.invokeMethod(app, "quit", Qt.ConnectionType.QueuedConnection) except Exception as e: - logging.error(f"Error during reload: {e}") + _log.log_error("Error during reload", e) os._exit(0) diff --git a/src/core/utils/css_processor.py b/src/core/utils/css_processor.py index 77fc02da6..ceafca14e 100644 --- a/src/core/utils/css_processor.py +++ b/src/core/utils/css_processor.py @@ -3,6 +3,7 @@ import re from typing import Dict, Set +import pretty_log as _log class CSSProcessor: """ @@ -38,7 +39,7 @@ def _read_css_file(self, file_path: str) -> str: with open(file_path, "r", encoding="utf-8") as file: return file.read() except (FileNotFoundError, OSError) as e: - logging.error(f"CSSProcessor Error '{file_path}': {e}") + _log.log_error(f"CSSProcessor Error '{file_path}'", e) return "" def _remove_comments(self, css: str) -> str: diff --git a/src/core/utils/update_service.py b/src/core/utils/update_service.py index 5c02d8891..b7304a1bf 100644 --- a/src/core/utils/update_service.py +++ b/src/core/utils/update_service.py @@ -24,6 +24,8 @@ from core.utils.utilities import ToastNotifier, app_data_path, get_app_identifier, get_architecture from settings import APP_ID, BUILD_VERSION, RELEASE_CHANNEL, SCRIPT_PATH +import pretty_log as _log + # GitHub API configuration GITHUB_API_URL = "https://api.github.com/repos/amnweb/yasb/releases/latest" GITHUB_API_DEV_URL = "https://api.github.com/repos/amnweb/yasb/releases/tags/dev" @@ -275,10 +277,10 @@ def check_for_updates( logging.warning(f"Network error checking for updates: {e.reason}") raise except json.JSONDecodeError as e: - logging.error(f"Failed to parse GitHub API response: {e}") + _log.log_error("Failed to parse GitHub API response", e) raise ValueError("Invalid JSON response from GitHub API") except Exception as e: - logging.error(f"Unexpected error checking for updates: {e}") + _log.log_error("Unexpected error checking for updates", e) raise def should_check_for_updates(self) -> bool: diff --git a/src/core/utils/widget_builder.py b/src/core/utils/widget_builder.py index 5d2e4c6e6..0bdc7a385 100644 --- a/src/core/utils/widget_builder.py +++ b/src/core/utils/widget_builder.py @@ -10,6 +10,8 @@ from core.utils.alert_dialog import raise_info_alert from settings import DEFAULT_CONFIG_FILENAME +import pretty_log as _log + class WidgetBuilder(QObject): def __init__(self, widget_configs: dict): diff --git a/src/core/utils/win32/app_icons.py b/src/core/utils/win32/app_icons.py index bcf19376e..e75aaaf16 100644 --- a/src/core/utils/win32/app_icons.py +++ b/src/core/utils/win32/app_icons.py @@ -29,6 +29,8 @@ from core.utils.win32.constants import PROCESS_QUERY_LIMITED_INFORMATION, SHGSI_ICON, SHGSI_LARGEICON from core.utils.win32.structs import BITMAP, BITMAPINFO, BITMAPINFOHEADER, ICONINFO, SHSTOCKICONINFO +import pretty_log as _log + pil_logger = logging.getLogger("PIL") pil_logger.setLevel(logging.INFO) @@ -174,7 +176,7 @@ def _is_fully_transparent(img: Image.Image) -> bool: return None except Exception as e: - logging.error(f"Error fetching icon: {e}") + _log.log_error("Error fetching icon", e) return None @@ -410,5 +412,5 @@ def get_stock_icon(icon_id: int) -> Image.Image | None: pass except Exception as e: - logging.error(f"Error getting stock icon {icon_id}: {e}") + _log.log_error(f"Error getting stock icon {icon_id}", e) return None diff --git a/src/core/utils/win32/utilities.py b/src/core/utils/win32/utilities.py index 49bafe3a4..f7a8f4d1e 100644 --- a/src/core/utils/win32/utilities.py +++ b/src/core/utils/win32/utilities.py @@ -32,6 +32,8 @@ SW_MAXIMIZE, ) +import pretty_log as _log + def get_monitor_hwnd(window_hwnd: int) -> int: return int(MonitorFromWindow(window_hwnd)) @@ -349,7 +351,7 @@ def is_valid(name): if screen.geometry().contains(pos) and is_valid(screen.name()): return screen.name() except Exception as e: - logging.error(f"Exception in follow_mouse: {e}") + _log.log_error("Exception in follow_mouse", e) if follow_window: hwnd = win32gui.GetForegroundWindow() @@ -384,7 +386,7 @@ def enable_autostart(app_name: str, executable_path: str) -> bool: logging.info(f"{app_name} added to startup") return True except Exception as e: - logging.error(f"Failed to add {app_name} to startup: {e}") + _log.log_error(f"Failed to add {app_name} to startup", e) return False @@ -400,7 +402,7 @@ def disable_autostart(app_name: str) -> bool: logging.info(f"Startup entry for {app_name} not found") return True except Exception as e: - logging.error(f"Failed to remove {app_name} from startup: {e}") + _log.log_error(f"Failed to remove {app_name} from startup", e) return False @@ -413,5 +415,5 @@ def is_autostart_enabled(app_name: str) -> bool: except WindowsError: return False except Exception as e: - logging.error(f"Failed to check startup status for {app_name}: {e}") + _log.log_error(f"Failed to check startup status for {app_name}", e) return False diff --git a/src/core/utils/win32/window_actions.py b/src/core/utils/win32/window_actions.py index d14682949..6f2cfe68f 100644 --- a/src/core/utils/win32/window_actions.py +++ b/src/core/utils/win32/window_actions.py @@ -7,6 +7,8 @@ from core.utils.win32.bindings import kernel32 as k32 from core.utils.win32.bindings import user32 as u32 +import pretty_log as _log + # --- Resolution helpers --- @@ -209,7 +211,7 @@ def close_application(hwnd: int, force: bool = False): try: _, process_id = win32process.GetWindowThreadProcessId(hwnd) except Exception as e: - logging.error(f"Failed to get process ID for HWND {hwnd}: {e}") + _log.log_error(f"Failed to get process ID for HWND {hwnd}", e) return if not process_id: @@ -247,7 +249,7 @@ def close_application(hwnd: int, force: bool = False): k32.CloseHandle(process_handle) except Exception as term_ex: - logging.error(f"Failed to terminate process {process_id}: {term_ex}") + _log.log_error(f"Failed to terminate process {process_id}", term_ex) else: # Graceful close path @@ -286,4 +288,4 @@ def close_application(hwnd: int, force: bool = False): logging.warning(f"EndTask unavailable/failed for HWND {target_hwnd}: {et_ex}") except Exception as e: - logging.error(f"Failed to close window {hwnd}: {e}") + _log.log_error(f"Failed to close window {hwnd}", e) diff --git a/src/main.py b/src/main.py index 1e75e0cf0..c7e5577dc 100644 --- a/src/main.py +++ b/src/main.py @@ -7,6 +7,7 @@ from sys import argv import win32api import winreg +import subprocess def get_windows_version(): # Read core OS information from the registry @@ -43,7 +44,7 @@ def get_windows_version(): from core.watcher import create_observer from env_loader import load_env, set_font_engine -import log as _log +import pretty_log as _log @contextlib.contextmanager @@ -125,9 +126,14 @@ def main(): simple_windows_version = lambda: f"Windows {platform.release()}, Build {platform.version()}" logging.info("Retrieved minimal OS information (may be innacurate).") logging.info(f" | {simple_windows_version}") - except BaseException as e: + except BaseException as e2: logging.warning("Failed to retrieve OS information.") + logging.info("YASB info:") + version = subprocess.check_output(['yasbc', '--version']).decode().split("\n") + logging.info(" | version (Main): %r", version[0].replace('\r', '')) + logging.info(" | version (CLI): %r", version[1].replace('\r', '')) + # Application instance should be created first app = QApplication(argv) app.setQuitOnLastWindowClosed(False) From 2476ac5ef7a87bccf7b7ced4ccc2cb1a4a8a5db5 Mon Sep 17 00:00:00 2001 From: Sandu Bogdan Date: Mon, 8 Dec 2025 18:26:07 +0200 Subject: [PATCH 3/5] Visual fixes --- src/core/bar.py | 3 +-- src/core/bar_helper.py | 5 ++--- src/core/bar_manager.py | 4 ++-- src/core/config.py | 3 +-- src/core/tray.py | 8 +++---- src/core/utils/controller.py | 2 +- src/core/utils/css_processor.py | 1 + src/core/utils/update_service.py | 3 +-- src/core/utils/widget_builder.py | 2 -- src/core/utils/win32/app_icons.py | 3 +-- src/core/utils/win32/utilities.py | 3 +-- src/core/utils/win32/window_actions.py | 3 +-- src/main.py | 29 ++++++++++++-------------- 13 files changed, 28 insertions(+), 41 deletions(-) diff --git a/src/core/bar.py b/src/core/bar.py index b372cc117..1649cc569 100644 --- a/src/core/bar.py +++ b/src/core/bar.py @@ -5,6 +5,7 @@ from PyQt6.QtGui import QScreen from PyQt6.QtWidgets import QFrame, QGridLayout, QHBoxLayout, QWidget +import pretty_log as _log from core.bar_helper import AutoHideManager, BarContextMenu, FullscreenManager, OsThemeManager from core.event_service import EventService from core.utils.utilities import is_valid_percentage_str, percent_to_float @@ -14,8 +15,6 @@ from core.validation.bar import BAR_DEFAULTS from settings import APP_BAR_TITLE -import pretty_log as _log - try: from core.utils.win32 import app_bar diff --git a/src/core/bar_helper.py b/src/core/bar_helper.py index 1b6c50c1d..6bc1f9e57 100644 --- a/src/core/bar_helper.py +++ b/src/core/bar_helper.py @@ -21,14 +21,13 @@ QWidgetAction, ) +import pretty_log as _log from core.utils.controller import exit_application, reload_application from core.utils.utilities import refresh_widget_style from core.utils.win32.bindings import DwmGetWindowAttribute from core.utils.win32.constants import DWMWA_CLOAKED, S_OK from core.utils.win32.utilities import apply_qmenu_style, get_monitor_hwnd, get_window_rect -import pretty_log as _log - class AutoHideZone(QFrame): """A transparent zone at the edge of the screen to detect when to show the bar""" @@ -419,7 +418,7 @@ def detect_os_theme(self) -> bool: value, _ = winreg.QueryValueEx(key, "AppsUseLightTheme") return value == 0 except Exception as e: - _log.log_error(f"Failed to determine Windows theme", e) + _log.log_error("Failed to determine Windows theme", e) return False def update_theme_class(self): diff --git a/src/core/bar_manager.py b/src/core/bar_manager.py index 7ce0f645e..6d01915a4 100644 --- a/src/core/bar_manager.py +++ b/src/core/bar_manager.py @@ -7,6 +7,7 @@ from PyQt6.QtGui import QScreen from PyQt6.QtWidgets import QApplication +import pretty_log as _log from core.bar import Bar from core.config import get_config, get_stylesheet from core.event_service import EventService @@ -15,7 +16,6 @@ from core.utils.utilities import get_screen_by_name from core.utils.widget_builder import WidgetBuilder -import pretty_log as _log class BarManager(QObject): styles_modified = pyqtSignal() @@ -54,7 +54,7 @@ def on_config_modified(self): try: config = get_config(show_error_dialog=True) except Exception as e: - _log.log_error(f"Error loading config", e) + _log.log_error("Error loading config", e) return if config and (config != self.config): if any( diff --git a/src/core/config.py b/src/core/config.py index 1f61c66be..17983c98b 100644 --- a/src/core/config.py +++ b/src/core/config.py @@ -13,13 +13,12 @@ from yaml import dump, safe_load from yaml.parser import ParserError +import pretty_log as _log import settings from core.utils.alert_dialog import raise_info_alert from core.utils.css_processor import CSSProcessor from core.validation.config import CONFIG_SCHEMA -import pretty_log as _log - SRC_CONFIGURATION_DIR = os.path.dirname(sys.executable) if getattr(sys, "frozen", False) else os.path.dirname(argv[0]) HOME_CONFIGURATION_DIR = path.join(Path.home(), settings.DEFAULT_CONFIG_DIRECTORY) HOME_STYLES_PATH = path.normpath(path.join(HOME_CONFIGURATION_DIR, settings.DEFAULT_STYLES_FILENAME)) diff --git a/src/core/tray.py b/src/core/tray.py index 791d25d5f..618b72f60 100644 --- a/src/core/tray.py +++ b/src/core/tray.py @@ -1,4 +1,3 @@ -import logging import os import shutil import subprocess @@ -10,6 +9,7 @@ from PyQt6.QtGui import QCursor, QIcon from PyQt6.QtWidgets import QMenu, QSystemTrayIcon +import pretty_log as _log from core.bar_manager import BarManager from core.config import get_config from core.ui.windows.about import AboutDialog @@ -22,8 +22,6 @@ SCRIPT_PATH, ) -import pretty_log as _log - VBS_PATH = os.path.join(SCRIPT_PATH, "yasb.vbs") EXE_PATH = os.path.join(SCRIPT_PATH, "yasb.exe") THEME_EXE_PATH = os.path.join(SCRIPT_PATH, "yasb_themes.exe") @@ -63,7 +61,7 @@ def _load_config(self): try: config = get_config(show_error_dialog=True) except Exception as e: - _log.log_error(f"Error loading config", e) + _log.log_error("Error loading config", e) return if config["komorebi"]: self.komorebi_start = config["komorebi"]["start_command"] @@ -253,7 +251,7 @@ def _open_in_browser(self, url): try: webbrowser.open(url) except Exception as e: - _log.log_error(f"Failed to open browser", e) + _log.log_error("Failed to open browser", e) def _show_about_dialog(self): dialog = AboutDialog(self) diff --git a/src/core/utils/controller.py b/src/core/utils/controller.py index 01c4c1e4a..9121177fc 100644 --- a/src/core/utils/controller.py +++ b/src/core/utils/controller.py @@ -5,11 +5,11 @@ from PyQt6.QtCore import QMetaObject, QProcess, Qt from PyQt6.QtWidgets import QApplication +import pretty_log as _log from core.event_service import EventService from core.utils.cli_server import CliPipeHandler from core.utils.win32.utilities import find_focused_screen -import pretty_log as _log def reload_application(msg="Reloading Application..."): try: diff --git a/src/core/utils/css_processor.py b/src/core/utils/css_processor.py index ceafca14e..19be740af 100644 --- a/src/core/utils/css_processor.py +++ b/src/core/utils/css_processor.py @@ -5,6 +5,7 @@ import pretty_log as _log + class CSSProcessor: """ Processes CSS files: handles @import, CSS variables, and removes comments. diff --git a/src/core/utils/update_service.py b/src/core/utils/update_service.py index b7304a1bf..e91f5e5af 100644 --- a/src/core/utils/update_service.py +++ b/src/core/utils/update_service.py @@ -21,11 +21,10 @@ import certifi +import pretty_log as _log from core.utils.utilities import ToastNotifier, app_data_path, get_app_identifier, get_architecture from settings import APP_ID, BUILD_VERSION, RELEASE_CHANNEL, SCRIPT_PATH -import pretty_log as _log - # GitHub API configuration GITHUB_API_URL = "https://api.github.com/repos/amnweb/yasb/releases/latest" GITHUB_API_DEV_URL = "https://api.github.com/repos/amnweb/yasb/releases/tags/dev" diff --git a/src/core/utils/widget_builder.py b/src/core/utils/widget_builder.py index 0bdc7a385..5d2e4c6e6 100644 --- a/src/core/utils/widget_builder.py +++ b/src/core/utils/widget_builder.py @@ -10,8 +10,6 @@ from core.utils.alert_dialog import raise_info_alert from settings import DEFAULT_CONFIG_FILENAME -import pretty_log as _log - class WidgetBuilder(QObject): def __init__(self, widget_configs: dict): diff --git a/src/core/utils/win32/app_icons.py b/src/core/utils/win32/app_icons.py index e75aaaf16..c8a06813f 100644 --- a/src/core/utils/win32/app_icons.py +++ b/src/core/utils/win32/app_icons.py @@ -12,6 +12,7 @@ from PIL import Image from win32con import DIB_RGB_COLORS +import pretty_log as _log from core.utils.win32.aumid import GetApplicationUserModelId, get_aumid_for_window from core.utils.win32.aumid_icons import get_icon_for_aumid from core.utils.win32.bindings import ( @@ -29,8 +30,6 @@ from core.utils.win32.constants import PROCESS_QUERY_LIMITED_INFORMATION, SHGSI_ICON, SHGSI_LARGEICON from core.utils.win32.structs import BITMAP, BITMAPINFO, BITMAPINFOHEADER, ICONINFO, SHSTOCKICONINFO -import pretty_log as _log - pil_logger = logging.getLogger("PIL") pil_logger.setLevel(logging.INFO) diff --git a/src/core/utils/win32/utilities.py b/src/core/utils/win32/utilities.py index f7a8f4d1e..13c164ac2 100644 --- a/src/core/utils/win32/utilities.py +++ b/src/core/utils/win32/utilities.py @@ -13,6 +13,7 @@ from win32gui import GetClassName, GetWindowPlacement, GetWindowRect, GetWindowText from winrt.windows.management.deployment import PackageManager +import pretty_log as _log from core.utils.utilities import is_windows_10 from core.utils.win32.bindings import ( CloseHandle, @@ -32,8 +33,6 @@ SW_MAXIMIZE, ) -import pretty_log as _log - def get_monitor_hwnd(window_hwnd: int) -> int: return int(MonitorFromWindow(window_hwnd)) diff --git a/src/core/utils/win32/window_actions.py b/src/core/utils/win32/window_actions.py index 6f2cfe68f..c8a3df437 100644 --- a/src/core/utils/win32/window_actions.py +++ b/src/core/utils/win32/window_actions.py @@ -4,11 +4,10 @@ import win32con import win32process +import pretty_log as _log from core.utils.win32.bindings import kernel32 as k32 from core.utils.win32.bindings import user32 as u32 -import pretty_log as _log - # --- Resolution helpers --- diff --git a/src/main.py b/src/main.py index c7e5577dc..20ff3d52f 100644 --- a/src/main.py +++ b/src/main.py @@ -2,23 +2,20 @@ import contextlib import ctypes import logging +import subprocess import sys import time -from sys import argv -import win32api import winreg -import subprocess +from sys import argv + def get_windows_version(): # Read core OS information from the registry - key = winreg.OpenKey( - winreg.HKEY_LOCAL_MACHINE, - r"SOFTWARE\Microsoft\Windows NT\CurrentVersion" - ) + key = winreg.OpenKey(winreg.HKEY_LOCAL_MACHINE, r"SOFTWARE\Microsoft\Windows NT\CurrentVersion") - product_name = winreg.QueryValueEx(key, "ProductName")[0] + product_name = winreg.QueryValueEx(key, "ProductName")[0] current_build = winreg.QueryValueEx(key, "CurrentBuild")[0] - ubr = winreg.QueryValueEx(key, "UBR")[0] + ubr = winreg.QueryValueEx(key, "UBR")[0] # Construct full build string full_build = f"{current_build}.{ubr}" @@ -30,9 +27,11 @@ def get_windows_version(): return f"{product_name}, Build {full_build}" + import qasync from PyQt6.QtWidgets import QApplication +import pretty_log as _log import settings from core.bar_manager import BarManager from core.config import get_config_and_stylesheet @@ -44,8 +43,6 @@ def get_windows_version(): from core.watcher import create_observer from env_loader import load_env, set_font_engine -import pretty_log as _log - @contextlib.contextmanager def single_instance_lock(name="yasb_reborn"): @@ -126,13 +123,13 @@ def main(): simple_windows_version = lambda: f"Windows {platform.release()}, Build {platform.version()}" logging.info("Retrieved minimal OS information (may be innacurate).") logging.info(f" | {simple_windows_version}") - except BaseException as e2: + except BaseException: logging.warning("Failed to retrieve OS information.") logging.info("YASB info:") - version = subprocess.check_output(['yasbc', '--version']).decode().split("\n") - logging.info(" | version (Main): %r", version[0].replace('\r', '')) - logging.info(" | version (CLI): %r", version[1].replace('\r', '')) + version = subprocess.check_output(["yasbc", "--version"]).decode().split("\n") + logging.info(" | version (Main): %r", version[0].replace("\r", "")) + logging.info(" | version (CLI): %r", version[1].replace("\r", "")) # Application instance should be created first app = QApplication(argv) @@ -177,7 +174,7 @@ def stop_observer(): if update_service.is_update_supported(): start_update_checker() except Exception as e: - _log.log_error(f"Failed to start auto update service", e) + _log.log_error("Failed to start auto update service", e) with loop: loop.run_forever() From 5575705e5436dd64cdd8d05a498b8d9e57df88d9 Mon Sep 17 00:00:00 2001 From: Sandu Bogdan Date: Mon, 8 Dec 2025 18:31:58 +0200 Subject: [PATCH 4/5] Change..? --- src/pretty_log.py | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) create mode 100644 src/pretty_log.py diff --git a/src/pretty_log.py b/src/pretty_log.py new file mode 100644 index 000000000..82bdfd2f6 --- /dev/null +++ b/src/pretty_log.py @@ -0,0 +1,19 @@ +import logging +import traceback +from typing import Any + + +def log_error(msg: str, error: BaseException | Exception | str | Any = ""): + if error: + if isinstance(error, BaseException): + tb_str = "".join(traceback.format_exception(type(error), error, error.__traceback__)) + else: + tb_str = "" + + if tb_str: + added_traceback = "\n #\n # " + str(tb_str).replace("\n", "\n # ") + else: + added_traceback = "" + logging.error(msg + ": \n # " + str(error).replace("\n", "\n # ") + added_traceback) + else: + logging.error(msg) From 33f0618d9cbb20e76bd8f522ad1822a0224449cd Mon Sep 17 00:00:00 2001 From: cornusandu <34373732+cornusandu@users.noreply.github.com> Date: Mon, 8 Dec 2025 19:24:03 +0200 Subject: [PATCH 5/5] Change back to 3.14 (Py Requirement) --- pyproject.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pyproject.toml b/pyproject.toml index d8c4b80cc..1c58e73ec 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -11,7 +11,7 @@ authors = [ ] license = "MIT" readme = "README.md" -requires-python = ">= 3.13" +requires-python = ">= 3.14" dependencies = [ "pyqt6==6.10.0", "cerberus",