deps: ruff обновлён до 0.16, код приведён к новому набору правил

- в 0.16 расширился набор правил по умолчанию: 29 срабатываний там, где 0.15
  давал "All checks passed"
- subprocess.run без явного check (PLW1510) — проставлен check=False там, где
  код и так разбирает returncode сам
- слепые except Exception в оркестраторе бэкапов и скриптах помечены
  noqa: BLE001 с объяснением, почему перехват намеренно широкий
- EXE001 и TRY004 отключены в pyproject: бит исполняемости в репозитории
  ничего не решает, а ValueError при разборе config.toml — про содержимое
  конфига, а не про тип аргумента
- ruff format в 0.16 форматирует python внутри markdown, из-за чего
  переформатирован пример в docs/drafts/gitea-runner-on-demand.md
This commit is contained in:
av
2026-09-06 17:33:22 +03:00
parent 7c57574723
commit 560fd2cc66
8 changed files with 69 additions and 48 deletions
+17 -7
View File
@@ -207,7 +207,9 @@ def measure_app_sizes(paths: list[Path]) -> dict[str, int]:
cmd = [DUST_BIN, "--output-json", "--output-format", "b", "--depth", "0"]
cmd += ["--no-progress", *(str(path) for path in paths)]
try:
result = subprocess.run(cmd, capture_output=True, text=True, timeout=600)
result = subprocess.run(
cmd, capture_output=True, text=True, timeout=600, check=False
)
except (OSError, subprocess.TimeoutExpired) as exc:
logger.warning("Failed to run %s: %s", DUST_BIN, exc)
return {}
@@ -410,7 +412,9 @@ class ResticStorage(Storage):
def __run_step(self, step: str, cmd: list[str], env: dict[str, str]) -> str | None:
"""Run a single restic command. Return None on success or error text."""
result = subprocess.run(cmd, env=env, capture_output=True, text=True)
result = subprocess.run(
cmd, env=env, capture_output=True, text=True, check=False
)
if result.returncode != 0:
error = result.stderr.strip() or result.stdout.strip() or "no output"
@@ -604,7 +608,9 @@ class BackupManager:
logger.info("Phases (forced): %s", ", ".join(self.forced_phases))
return self.forced_phases
phases = self.schedule.due_phases(datetime.now())
# Расписание фаз считается по календарным суткам локального времени
# сервера; aware-время в UTC сдвинуло бы границу суток.
phases = self.schedule.due_phases(datetime.now()) # noqa: DTZ005
logger.info("Phases (scheduled): %s", ", ".join(phases))
return phases
@@ -754,6 +760,7 @@ class BackupManager:
capture_output=True,
text=True,
timeout=3600, # 1 hour timeout
check=False,
)
if result.returncode == 0:
@@ -771,8 +778,9 @@ class BackupManager:
logger.error(error_msg)
self.errors.append(f"App {username}: {error_msg}")
return False
except Exception as e:
error_msg = f"Failed to run backup script {script_path}: {str(e)}"
# Падение одного дампа не должно ронять весь прогон.
except Exception as e: # noqa: BLE001
error_msg = f"Failed to run backup script {script_path}: {e!s}"
logger.error(error_msg)
self.errors.append(f"App {username}: {error_msg}")
return False
@@ -841,7 +849,8 @@ class BackupManager:
for notificator in self.notifiers:
try:
notificator.send(title, message)
except Exception as e:
# Недоступность одного нотификатора не должна ронять остальные.
except Exception as e: # noqa: BLE001
logger.error("Failed to send notification: %s", e)
@@ -981,7 +990,8 @@ def main() -> None:
except KeyboardInterrupt:
logger.info("Backup process interrupted by user")
sys.exit(130)
except Exception as e:
# Верхний уровень: любая неожиданная ошибка уходит в лог, а не в traceback.
except Exception as e: # noqa: BLE001
logger.error("Unexpected error in backup process: %s", e)
sys.exit(1)
+2 -2
View File
@@ -42,8 +42,8 @@ def main() -> None:
try:
filepath.unlink()
print(f"Deleted: {filename}")
except Exception as e:
print(f"Error deleting {filename}: {str(e)}")
except Exception as e: # noqa: BLE001
print(f"Error deleting {filename}: {e!s}")
if __name__ == "__main__":