Add ruff linting

Configure ruff in pyproject.toml and apply its fixes: modern annotations
(X | None, builtin generics, collections.abc), sorted imports, explicit
stacklevel in test warnings.
This commit is contained in:
Fuxino
2026-10-16 13:47:24 +02:00
parent 7dbb1bcaee
commit 17c104c6c8
6 changed files with 65 additions and 57 deletions
+33 -33
View File
@@ -14,27 +14,27 @@ Classes:
# Avoid evaluating annotations at definition time, as they reference optional modules (paramiko)
from __future__ import annotations
# Import libraries
import sys
import os
import pwd
import io
import re
from typing import Callable, Iterator, List, Optional, ParamSpec, TypedDict, TypeVar
import warnings
from functools import wraps
from shutil import get_terminal_size, rmtree, which
import shlex
import argparse
import configparser
import io
import logging
from logging import StreamHandler
from timeit import default_timer
from subprocess import Popen, PIPE, STDOUT
import os
import pwd
import re
import shlex
import sys
import warnings
from collections.abc import Callable, Iterator
from datetime import datetime
from tempfile import mkstemp
from functools import wraps
from getpass import GetPassWarning, getpass
from glob import glob
from logging import StreamHandler
from shutil import get_terminal_size, rmtree, which
from subprocess import PIPE, STDOUT, Popen
from tempfile import mkstemp
from timeit import default_timer
from typing import ParamSpec, TypedDict, TypeVar
try:
import paramiko
@@ -204,9 +204,9 @@ class Backup:
Perform the backup
"""
def __init__(self, inputs: Optional[List[str]], output: Optional[str], exclude: Optional[List[str]],
keep: Optional[int], options: str,
ssh_host: Optional[str] = None, ssh_user: Optional[str] = None, ssh_keyfile: Optional[str] = None,
def __init__(self, inputs: list[str] | None, output: str | None, exclude: list[str] | None,
keep: int | None, options: str,
ssh_host: str | None = None, ssh_user: str | None = None, ssh_keyfile: str | None = None,
remote_sudo: bool = False, remove_before: bool = False, verbose: bool = False,
progress: bool = False) -> None:
# Missing values are reported by check_params()
@@ -228,7 +228,7 @@ class Backup:
self._inputs_path = ''
self._exclude_path = ''
self._remote = False
self._ssh: Optional[paramiko.client.SSHClient] = None
self._ssh: paramiko.client.SSHClient | None = None
self._password_auth = False
self._removed_count = 0
@@ -281,7 +281,7 @@ class Backup:
return 0
def _resolve_remote_path(self, path: str) -> Optional[str]:
def _resolve_remote_path(self, path: str) -> str | None:
"""Return the absolute path of a directory on the server, or None if it doesn't exist"""
assert self._ssh is not None
@@ -450,7 +450,7 @@ class Backup:
except IndexError:
logger.info('No previous backups available')
def _ssh_connect(self, homedir: str = '') -> Optional[paramiko.client.SSHClient]:
def _ssh_connect(self, homedir: str = '') -> paramiko.client.SSHClient | None:
try:
ssh = paramiko.SSHClient()
except NameError:
@@ -469,7 +469,7 @@ class Backup:
if connected is None:
ssh.close()
def _ssh_login(self, ssh: paramiko.client.SSHClient, homedir: str) -> Optional[paramiko.client.SSHClient]:
def _ssh_login(self, ssh: paramiko.client.SSHClient, homedir: str) -> paramiko.client.SSHClient | None:
try:
ssh.load_host_keys(filename=f'{homedir}/.ssh/known_hosts')
except FileNotFoundError:
@@ -553,7 +553,7 @@ class Backup:
return ssh
def _load_ssh_key(self) -> Optional[paramiko.PKey]:
def _load_ssh_key(self) -> paramiko.PKey | None:
try:
return paramiko.PKey.from_path(self.ssh_keyfile)
except TypeError:
@@ -808,7 +808,7 @@ def _read_records(stream: io.BufferedIOBase) -> Iterator[str]:
yield buffer.decode('utf-8', errors='replace')
def _detect_user() -> Optional[str]:
def _detect_user() -> str | None:
if os.geteuid() == 0:
return os.getenv('SUDO_USER') or os.getenv('DOAS_USER')
@@ -873,8 +873,8 @@ def _expand_home(path: str, user: str) -> str:
return os.path.expanduser(path)
def _expand_inputs(inputs: List[str], user: Optional[str] = None) -> List[str]:
expanded_inputs: List[str] = []
def _expand_inputs(inputs: list[str], user: str | None = None) -> list[str]:
expanded_inputs: list[str] = []
for i in inputs:
if i == '':
@@ -900,13 +900,13 @@ def _expand_inputs(inputs: List[str], user: Optional[str] = None) -> List[str]:
class ConfigArgs(TypedDict):
"""Values read from the configuration file"""
inputs: Optional[List[str]]
output: Optional[str]
exclude: Optional[List[str]]
inputs: list[str] | None
output: str | None
exclude: list[str] | None
keep: int
ssh_host: Optional[str]
ssh_user: Optional[str]
ssh_keyfile: Optional[str]
ssh_host: str | None
ssh_user: str | None
ssh_keyfile: str | None
remote_sudo: bool
numeric_ids: bool
@@ -919,7 +919,7 @@ def _get_bool(config: configparser.ConfigParser, key: str) -> bool:
return config.getboolean('server', key)
def _read_config(config_file: str, user: Optional[str] = None) -> ConfigArgs:
def _read_config(config_file: str, user: str | None = None) -> ConfigArgs:
config_args: ConfigArgs = {'inputs': None,
'output': None,
'exclude': None,