fix: resolve all current lint errors

This commit is contained in:
dark_zoul committed 2026-10-19 22:46:47 +03:00
1 parent 972c8e1dbf
commit 8904e07597
11 files changed
+64 -51

No files matched your search

+5 -2
View File
@@ -1,10 +1,13 @@
from __future__ import annotations
import json
import logging
import os
from pathlib import Path
from typing import Any
logger = logging.getLogger(__name__)
def _default_ffmpeg_path() -> str:
if os.name == "nt":
@@ -40,9 +43,9 @@ class Settings:
def _load_from_path(self, path: Path) -> None:
try:
self.data.update(json.loads(path.read_text(encoding="utf-8")))
except Exception:
except (OSError, TypeError, UnicodeError, ValueError) as exc:
# Leave defaults if invalid JSON; validation can be added later.
pass
logger.debug("Failed to load config %s: %s", path, exc)
def _write_default_config(self, path: Path) -> None:
path.parent.mkdir(parents=True, exist_ok=True)
+7 -4
View File
@@ -1,10 +1,13 @@
from __future__ import annotations
import logging
import sys
from pathlib import Path
from PySide6 import QtGui, QtWidgets
logger = logging.getLogger(__name__)
def _resource_base() -> Path:
# PyInstaller sets sys._MEIPASS to the temp extraction dir.
@@ -31,16 +34,16 @@ def load_app_icon() -> QtGui.QIcon:
icon = QtGui.QIcon(str(p))
if not icon.isNull():
return icon
except Exception:
pass
except Exception as exc: # noqa: BLE001 - icon loading is best effort
logger.debug("Failed to load app icon from %s: %s", p, exc)
# Fallback to a platform theme icon (Linux) or a generic icon.
try:
themed = QtGui.QIcon.fromTheme("applications-multimedia")
if not themed.isNull():
return themed
except Exception:
pass
except Exception as exc: # noqa: BLE001 - themed icon loading is best effort
logger.debug("Failed to load themed app icon: %s", exc)
return QtWidgets.QApplication.style().standardIcon(QtWidgets.QStyle.StandardPixmap.SP_ComputerIcon)
+1 -1
View File
@@ -15,7 +15,7 @@ class AppConfig:
def load_config(path: Path) -> AppConfig:
raw = json.loads(path.read_text(encoding="utf-8"))
if not isinstance(raw, dict):
raise ValueError("config root must be a JSON object")
raise TypeError("config root must be a JSON object")
return AppConfig(data=raw, path=path)
+34 -26
View File
@@ -1,5 +1,6 @@
from __future__ import annotations
import logging
import sys
import threading
@@ -17,6 +18,8 @@ from .pages.queue import QueuePage
from .pages.settings import SettingsPage
from .runner import SyncRequest, SyncRunner
logger = logging.getLogger(__name__)
class MainWindow(QtWidgets.QMainWindow):
def __init__(self) -> None:
@@ -90,8 +93,8 @@ class MainWindow(QtWidgets.QMainWindow):
if cfg_path is not None:
try:
self._settings_page.set_config_path(cfg_path)
except Exception:
pass
except Exception as exc: # noqa: BLE001 - optional settings-page wiring
logger.debug("Failed to set settings config path: %s", exc)
self._playlists_page.cancel_requested.connect(self._cancel_sync)
self._queue_page.cancel_sync_requested.connect(self._cancel_sync)
@@ -138,7 +141,8 @@ class MainWindow(QtWidgets.QMainWindow):
tray = ui.get("tray")
tray = tray if isinstance(tray, dict) else {}
return dict(tray)
except Exception:
except Exception as exc: # noqa: BLE001 - config fallback keeps the UI usable
logger.debug("Failed to load tray configuration: %s", exc)
return {}
def _close_to_tray_enabled(self) -> bool:
@@ -158,7 +162,8 @@ class MainWindow(QtWidgets.QMainWindow):
try:
if not QtWidgets.QSystemTrayIcon.isSystemTrayAvailable():
return
except Exception:
except Exception as exc: # noqa: BLE001 - tray support is optional
logger.debug("Failed to check system tray availability: %s", exc)
return
icon = load_app_icon()
@@ -211,27 +216,30 @@ class MainWindow(QtWidgets.QMainWindow):
QtWidgets.QSystemTrayIcon.MessageIcon.Information,
3000,
)
except Exception:
pass
except Exception as exc: # noqa: BLE001 - tray notification is best effort
logger.debug("Failed to show tray notification: %s", exc)
return
if self._tray is not None and not self._close_to_tray_enabled():
# Explicitly quit, because the app may be configured to keep running without windows.
try:
event.accept()
except Exception:
pass
except Exception as exc: # noqa: BLE001 - close event acceptance is best effort
logger.debug("Failed to accept close event: %s", exc)
QtWidgets.QApplication.quit()
return
super().closeEvent(event)
def changeEvent(self, event: QtCore.QEvent) -> None: # type: ignore[override]
try:
if event.type() == QtCore.QEvent.Type.WindowStateChange:
if self._tray is not None and self._minimize_to_tray_enabled():
if bool(self.windowState() & QtCore.Qt.WindowState.WindowMinimized):
QtCore.QTimer.singleShot(0, self.hide)
except Exception:
pass
if (
event.type() == QtCore.QEvent.Type.WindowStateChange
and self._tray is not None
and self._minimize_to_tray_enabled()
and bool(self.windowState() & QtCore.Qt.WindowState.WindowMinimized)
):
QtCore.QTimer.singleShot(0, self.hide)
except Exception as exc: # noqa: BLE001 - window state handling is best effort
logger.debug("Failed to handle window state change: %s", exc)
super().changeEvent(event)
def _refresh_queue_labels(self) -> None:
@@ -244,24 +252,24 @@ class MainWindow(QtWidgets.QMainWindow):
pid = extract_playlist_id(url) or url
labels[pid] = str(pl.get("name") or f"Playlist {idx}")
self._queue_page.set_playlist_labels(labels)
except Exception:
pass
except Exception as exc: # noqa: BLE001 - queue labels are best effort
logger.debug("Failed to refresh queue labels: %s", exc)
@QtCore.Slot(str, dict)
def _on_bus_event(self, name: str, payload: dict) -> None:
# Fan out to interested pages.
try:
self._queue_page.on_event(name, payload)
except Exception:
pass
except Exception as exc: # noqa: BLE001 - page event fan-out is isolated
logger.debug("Queue page event handler failed: %s", exc)
try:
self._logs_page.on_event(name, payload)
except Exception:
pass
except Exception as exc: # noqa: BLE001 - page event fan-out is isolated
logger.debug("Logs page event handler failed: %s", exc)
try:
self._playlists_page.on_event(name, payload)
except Exception:
pass
except Exception as exc: # noqa: BLE001 - page event fan-out is isolated
logger.debug("Playlists page event handler failed: %s", exc)
# Auto-pause on YouTube bot-check/rate-limit surface.
if name == "SyncPaused":
@@ -315,8 +323,8 @@ class MainWindow(QtWidgets.QMainWindow):
try:
self._thread.quit()
self._thread.wait(2000)
except Exception:
pass
except Exception as exc: # noqa: BLE001 - thread shutdown is best effort
logger.debug("Failed to stop sync thread: %s", exc)
self._runner = None
self._cancel_flag = None
self._pause_flag = None
@@ -330,8 +338,8 @@ class MainWindow(QtWidgets.QMainWindow):
if cfg_path is not None:
self._settings_page.set_config_path(cfg_path)
self._refresh_queue_labels()
except Exception:
pass
except Exception as exc: # noqa: BLE001 - config refresh is best effort
logger.debug("Failed to refresh configuration after sync: %s", exc)
# Continue "sync all" chain if active.
if hasattr(self, "_sync_queue") and self._sync_queue:
+1 -1
View File
@@ -38,7 +38,7 @@ class LogsPage(QtWidgets.QWidget):
# Keep this lightweight: append a single-line JSON entry.
try:
line = json.dumps({"event": name, **payload}, ensure_ascii=False)
except Exception:
except Exception: # noqa: BLE001 - fall back to a readable representation
line = f"{name}: {payload}"
self._text.appendPlainText(line)
self._text.moveCursor(self._text.textCursor().End)
+9 -10
View File
@@ -137,7 +137,7 @@ class PlaylistManagerPage(QtWidgets.QWidget):
raise RuntimeError("Config path not available")
self._config = normalize_config(load_config(self._config_path).data)
rows = self._rows_from_settings()
except Exception as exc:
except Exception as exc: # noqa: BLE001 - show config load failures in the UI
self._status.setText(f"Failed to load config: {exc}")
return
finally:
@@ -152,7 +152,7 @@ class PlaylistManagerPage(QtWidgets.QWidget):
ls = db.get_playlist_last_sync(pid)
if ls:
last_sync_by_id[pid] = str(ls)
except Exception:
except Exception: # noqa: BLE001 - database metadata is optional
last_sync_by_id = {}
self._list.clear()
@@ -256,7 +256,7 @@ class PlaylistManagerPage(QtWidgets.QWidget):
self._status.setText(f"Saved {len(data['playlists'])} playlists to {self._config_path}.")
# Reload settings to reflect merged defaults
self.reload_from_config()
except Exception as exc:
except Exception as exc: # noqa: BLE001 - show config save failures in the UI
self._status.setText(f"Failed to save config: {exc}")
def _reindex_cards(self) -> None:
@@ -302,7 +302,7 @@ class PlaylistManagerPage(QtWidgets.QWidget):
data["playlists"] = self._table_to_playlists()
save_config(self._config_path, data)
self._status.setText(f"Autosaved to {self._config_path}.")
except Exception as exc:
except Exception as exc: # noqa: BLE001 - show autosave failures in the UI
self._status.setText(f"Autosave failed: {exc}")
def on_event(self, name: str, payload: dict) -> None:
@@ -355,7 +355,7 @@ class PlaylistManagerPage(QtWidgets.QWidget):
self._download_state_by_pid[pid]["video_id"] = vid
self._download_state_by_pid[pid]["status"] = str(payload.get("status") or "downloading")
self._set_card_progress(pid, p)
pct = int(round(max(0.0, min(1.0, p)) * 100))
pct = round(max(0.0, min(1.0, p)) * 100)
st = str(payload.get("status") or "downloading")
tail = f"{vid} {pct}%" if vid else f"{pct}%"
self._set_card_status(pid, f"{st} {tail}".strip())
@@ -392,9 +392,8 @@ class PlaylistManagerPage(QtWidgets.QWidget):
for i in range(self._list.count()):
item = self._list.item(i)
w = self._list.itemWidget(item)
if isinstance(w, _PlaylistCard):
if w.playlist_id() == playlist_id:
w.set_status(text)
if isinstance(w, _PlaylistCard) and w.playlist_id() == playlist_id:
w.set_status(text)
def _set_card_last_sync(self, playlist_id: str, last_sync: str) -> None:
for i in range(self._list.count()):
@@ -604,7 +603,7 @@ class _PlaylistCard(QtWidgets.QFrame):
return extract_playlist_id(url) or url
def set_progress(self, progress: float) -> None:
pct = max(0, min(100, int(round(progress * 100))))
pct = max(0, min(100, round(progress * 100)))
self._progress.setValue(pct)
def set_last_sync(self, last_sync: str) -> None:
@@ -613,7 +612,7 @@ class _PlaylistCard(QtWidgets.QFrame):
def validate(self) -> list[str]:
errs: list[str] = []
url = self._url.text().strip()
if not url or not (url.startswith("http://") or url.startswith("https://")):
if not url or not url.startswith(("http://", "https://")):
errs.append("URL required")
mode = self._mode.currentText().strip()
if mode not in {"video", "audio", "both"}:
+1 -1
View File
@@ -141,7 +141,7 @@ class QueuePage(QtWidgets.QWidget):
status_item.setText(str(payload.get("status") or "downloading"))
prog = payload.get("progress")
if isinstance(prog, (int, float)):
pct = max(0, min(100, int(round(prog * 100))))
pct = max(0, min(100, round(prog * 100)))
bar = self._table.cellWidget(row, 3)
if bar is None:
bar = QtWidgets.QProgressBar()
+2 -2
View File
@@ -126,7 +126,7 @@ class SettingsPage(QtWidgets.QWidget):
self._start_minimized_to_tray.setChecked(bool(tray.get("start_minimized_to_tray", False)))
self._status.setText(f"Loaded settings from {self._config_path}.")
except Exception as exc:
except Exception as exc: # noqa: BLE001 - show load failures in the UI
self._status.setText(f"Failed to load settings: {exc}")
finally:
self._suppress_autosave = False
@@ -161,5 +161,5 @@ class SettingsPage(QtWidgets.QWidget):
save_config(self._config_path, data)
self._status.setText(f"Saved settings to {self._config_path}.")
except Exception as exc:
except Exception as exc: # noqa: BLE001 - show save failures in the UI
self._status.setText(f"Failed to save settings: {exc}")
+1 -1
View File
@@ -70,5 +70,5 @@ class SyncRunner(QtCore.QObject):
self.finished.emit(False, "cancelled")
else:
self.finished.emit(True, "done")
except Exception as exc:
except Exception as exc: # noqa: BLE001 - report worker failures through the UI signal
self.finished.emit(False, str(exc))
+2 -2
View File
@@ -19,7 +19,7 @@ class _SmoothWheelFilter(QtCore.QObject):
try:
angle_y = wheel.angleDelta().y()
pixel_y = wheel.pixelDelta().y()
except Exception:
except Exception: # noqa: BLE001 - fall back to native scrolling for unknown event types
return super().eventFilter(obj, event)
dy = pixel_y if pixel_y else angle_y
@@ -34,7 +34,7 @@ class _SmoothWheelFilter(QtCore.QObject):
if pixel_y:
delta = -dy
else:
delta = int(round(-dy / 120.0 * base_step))
delta = round(-dy / 120.0 * base_step)
target = max(sb.minimum(), min(sb.maximum(), start + delta))
if target == start:
+1 -1
View File
@@ -37,7 +37,7 @@ def test_executor_emits_sync_events(tmp_path):
assert "SyncSummary" in names
assert "SyncFinished" in names
summary = [p for n, p in published if n == "SyncSummary"][0]
summary = next(p for n, p in published if n == "SyncSummary")
assert summary["playlist_id"] == "p"
assert "duration_s" in summary
assert isinstance(summary["counts"], dict)