style: say which lint rules this repo keeps, then keep them

`[tool.ruff]` set a line length and a target version and nothing else, so which
rules ran depended on the installed ruff's defaults — fine while nobody ran it,
not fine for a CI job that can turn a push red because a tool changed its mind.

The set is named explicitly (E, F, I, UP, SIM, B, RUF) with three ignores that
are each a real decision rather than a shrug: B008, because FastAPI's whole
dependency idiom is a call in a default argument; E501, because wrapping prose
is a formatter's business; and RUF001, because the reports and the bot speak
Russian and "ambiguous character" is the wrong complaint about a string the
user is meant to read.

The 73 findings that remained are fixed — mostly `datetime.timezone.utc` →
`datetime.UTC`, `typing.Callable` → `collections.abc.Callable`, import order,
and unused `noqa` markers — plus seven by hand: `contextlib.suppress` for two
try/except/pass pairs, unpacking instead of list concatenation, one negated
return.

`ruff format` is deliberately *not* adopted: it would reformat 51 files, and
some of the layout here is hand-set (the comment tables, the DNS wire-format
structs) in ways a formatter flattens.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
timka123andClaude Opus 5 committed 2026-10-22 17:28:57 +03:00
1 parent 5facf41f10
commit ec7eedbc66
28 files changed
+84 -68

No files matched your search

+1 -1
View File
@@ -38,7 +38,7 @@ def _remote(verb: str) -> int:
from PyQt6.QtCore import QCoreApplication
from PyQt6.QtDBus import QDBusConnection, QDBusInterface
_app = QCoreApplication(sys.argv) # noqa: F841 - needed for the D-Bus loop
_app = QCoreApplication(sys.argv)
interface = QDBusInterface(
"org.kadence.Desktop", "/Timer", "org.kadence.Timer", QDBusConnection.sessionBus()
)
+5 -6
View File
@@ -12,6 +12,7 @@ hostname, so the worst a compromised client can do is block a site.
from __future__ import annotations
import contextlib
import logging
import os
import re
@@ -35,7 +36,7 @@ def valid_hostname(name: str) -> bool:
def current_block() -> list[str]:
"""The hostnames currently inside our managed region of `/etc/hosts`."""
try:
with open(HOSTS_PATH, "r", encoding="utf-8") as handle:
with open(HOSTS_PATH, encoding="utf-8") as handle:
lines = handle.read().splitlines()
except OSError:
return []
@@ -124,12 +125,10 @@ class HostsBlocker:
list_path = handle.name
os.chmod(list_path, 0o644) # the helper reads it as root from /tmp
try:
return self._run(runner + ["apply", "--ip", redirect_ip, "--file", list_path])
return self._run([*runner, "apply", "--ip", redirect_ip, "--file", list_path])
finally:
try:
with contextlib.suppress(OSError):
os.unlink(list_path)
except OSError:
pass
def clear(self) -> bool:
"""Remove the managed region. Safe to call when it is not there."""
@@ -138,7 +137,7 @@ class HostsBlocker:
runner = self._runner()
if runner is None:
return False
return self._run(runner + ["clear"])
return self._run([*runner, "clear"])
def _run(self, command: list[str]) -> bool:
try:
+2 -2
View File
@@ -26,8 +26,8 @@ from __future__ import annotations
import logging
import time
from collections.abc import Callable
from types import ModuleType
from typing import Callable
from kadence_desktop.blocking import processes
from kadence_desktop.blocking.hosts import HostsBlocker
@@ -262,7 +262,7 @@ class BlockerManager:
self._asked[identity] = now
self._announce(app, "killed")
def _announce(self, app: "processes.RunningApp", action: str) -> None:
def _announce(self, app: processes.RunningApp, action: str) -> None:
"""Report and notify, at most once per process per cooldown."""
if not self._claim_report(app.identity):
return
@@ -23,8 +23,8 @@ from __future__ import annotations
import logging
import os
import signal
from fnmatch import fnmatch
from dataclasses import dataclass
from fnmatch import fnmatch
from pathlib import Path
log = logging.getLogger(__name__)
+8 -9
View File
@@ -31,6 +31,7 @@ startup whenever a drop-in is found lying around.
from __future__ import annotations
import concurrent.futures
import contextlib
import fnmatch
import ipaddress
import logging
@@ -363,10 +364,8 @@ class StubResolver:
for sock in (self._udp, self._tcp):
if sock is None:
continue
try:
with contextlib.suppress(OSError):
sock.close() # the blocking recv/accept raises, ending the loop
except OSError:
pass
for thread in self._threads:
thread.join(timeout=1)
for pool in (self._handlers, self._forwards):
@@ -407,7 +406,7 @@ class StubResolver:
while self._running and self._udp is not None:
try:
data, address = self._udp.recvfrom(4096)
except socket.timeout:
except TimeoutError:
continue
except OSError:
break
@@ -431,7 +430,7 @@ class StubResolver:
while self._running and self._tcp is not None:
try:
connection, _ = self._tcp.accept()
except socket.timeout:
except TimeoutError:
continue
except OSError:
break
@@ -632,7 +631,7 @@ def _parse_nameserver(token: str) -> tuple[str, int] | None:
def _parse_resolv_conf(path: str) -> list[tuple[str, int]]:
servers: list[tuple[str, int]] = []
try:
with open(path, "r", encoding="utf-8", errors="replace") as handle:
with open(path, encoding="utf-8", errors="replace") as handle:
lines = handle.read().splitlines()
except OSError:
return servers
@@ -704,7 +703,7 @@ class ResolvedRoute:
def _read_dropin(self) -> tuple[tuple[str, ...], int] | None:
"""What the drop-in currently says, if it is one of ours."""
try:
with open(self.dropin_path, "r", encoding="utf-8") as handle:
with open(self.dropin_path, encoding="utf-8") as handle:
text = handle.read()
except OSError:
return None
@@ -739,7 +738,7 @@ class ResolvedRoute:
runner = self._runner()
if runner is None:
return False
command = runner + ["resolved-on", "--port", str(port), "--domains", ",".join(wanted)]
command = [*runner, "resolved-on", "--port", str(port), "--domains", ",".join(wanted)]
if not self._run(command, f"route {len(wanted)} zone(s) through the local stub"):
return False
self._applied = (wanted, port)
@@ -753,7 +752,7 @@ class ResolvedRoute:
runner = self._runner()
if runner is None:
return False
if not self._run(runner + ["resolved-off"], "stop routing DNS through the local stub"):
if not self._run([*runner, "resolved-off"], "stop routing DNS through the local stub"):
return False
self._applied = None
return True
+1 -1
View File
@@ -107,7 +107,7 @@ class DesktopConfig:
window: dict = field(default_factory=lambda: {"width": 1100, "height": 760})
@classmethod
def load(cls) -> "DesktopConfig":
def load(cls) -> DesktopConfig:
if not CONFIG_PATH.exists():
config = cls()
config.save()
@@ -19,7 +19,7 @@ every documented command then hits.
from __future__ import annotations
import logging
from typing import Callable
from collections.abc import Callable
from PyQt6.QtCore import QObject, pyqtClassInfo, pyqtSlot
from PyQt6.QtDBus import QDBusAbstractAdaptor, QDBusConnection
@@ -92,60 +92,60 @@ class TimerAdaptor(QDBusAbstractAdaptor):
# D-Bus methods are PascalCase by convention.
@pyqtSlot(result=str)
def StartWork(self) -> str: # noqa: N802
def StartWork(self) -> str:
"""Start a focus interval."""
return self._service.run("start_work")
@pyqtSlot(result=str)
def StartBreak(self) -> str: # noqa: N802
def StartBreak(self) -> str:
return self._service.run("start_break")
@pyqtSlot(result=str)
def Toggle(self) -> str: # noqa: N802
def Toggle(self) -> str:
"""Start if idle, pause if running, resume if paused — one hotkey."""
return self._service.run("toggle")
@pyqtSlot(result=str)
def Pause(self) -> str: # noqa: N802
def Pause(self) -> str:
return self._service.run("pause")
@pyqtSlot(result=str)
def Resume(self) -> str: # noqa: N802
def Resume(self) -> str:
return self._service.run("resume")
@pyqtSlot(result=str)
def Complete(self) -> str: # noqa: N802
def Complete(self) -> str:
return self._service.run("complete")
@pyqtSlot(result=str)
def Stop(self) -> str: # noqa: N802
def Stop(self) -> str:
return self._service.run("stop")
@pyqtSlot(result=str)
def Extend(self) -> str: # noqa: N802
def Extend(self) -> str:
return self._service.run("extend")
@pyqtSlot(result=str)
def Interrupt(self) -> str: # noqa: N802
def Interrupt(self) -> str:
"""Count a distraction without stopping the clock."""
return self._service.run("interrupt")
@pyqtSlot(result=str)
def Status(self) -> str: # noqa: N802
def Status(self) -> str:
"""One line: what is running and how much is left."""
return self._service.run("status")
@pyqtSlot(result=str)
def SendReport(self) -> str: # noqa: N802
def SendReport(self) -> str:
return self._service.run("send_report")
@pyqtSlot(result=str)
def ToggleMini(self) -> str: # noqa: N802
def ToggleMini(self) -> str:
"""Show or hide the floating mini timer."""
return self._service.run("toggle_mini")
@pyqtSlot(result=str)
def Raise(self) -> str: # noqa: N802
def Raise(self) -> str:
"""Show the main window (used by a second instance)."""
return self._service.run("raise_window")
@@ -155,9 +155,7 @@ def up_to_date(position: tuple[int, int] | None = None) -> bool:
if any(parser.get(section, key, fallback=None) != value for key, value in wanted.items()):
return False
# A position left over from a previous corner must not linger.
if position is None and parser.has_option(section, "position"):
return False
return True
return not (position is None and parser.has_option(section, "position"))
except (configparser.Error, OSError):
return False
@@ -10,7 +10,7 @@ so a running timer never stacks up a column of toasts.
from __future__ import annotations
import logging
from typing import Callable
from collections.abc import Callable
from PyQt6.QtCore import QMetaType, QObject, QVariant, pyqtSlot
from PyQt6.QtDBus import QDBusArgument, QDBusConnection, QDBusInterface, QDBusMessage
-1
View File
@@ -7,7 +7,6 @@ that silently puts a window half off the screen on somebody else's monitor.
from __future__ import annotations
import pytest
from kadence_desktop.integrations.placement import CORNER_LABELS, CORNERS, Rect, point_for
SCREEN = Rect(0, 0, 1536, 960)
-1
View File
@@ -18,7 +18,6 @@ import threading
from pathlib import Path
import pytest
from kadence_desktop.blocking.resolver import (
ResolvedRoute,
StubResolver,