From 1fb0513467daa1dac04722bb81896a5107ec8d8a Mon Sep 17 00:00:00 2001 From: Fuxino Date: Wed, 14 Oct 2026 08:33:45 +0200 Subject: [PATCH] Add type hints to the config reading functions Return a TypedDict from _read_config() and stop reusing variables for different types, so that mypy can check the config values. No change in behaviour. --- simple_backup/simple_backup.py | 78 ++++++++++++++++++---------------- 1 file changed, 41 insertions(+), 37 deletions(-) diff --git a/simple_backup/simple_backup.py b/simple_backup/simple_backup.py index ff28966..a32490e 100755 --- a/simple_backup/simple_backup.py +++ b/simple_backup/simple_backup.py @@ -18,7 +18,7 @@ from __future__ import annotations import sys import os import pwd -from typing import Callable, List, Optional, ParamSpec, TypeVar, Union +from typing import Callable, List, Optional, ParamSpec, TypedDict, TypeVar, Union import warnings from functools import wraps from shutil import rmtree, which @@ -766,8 +766,8 @@ def _expand_home(path: str, user: str) -> str: return os.path.expanduser(path) -def _expand_inputs(inputs, user: Optional[str] = None): - expanded_inputs = [] +def _expand_inputs(inputs: List[str], user: Optional[str] = None) -> List[str]: + expanded_inputs: List[str] = [] for i in inputs: if i == '': @@ -790,16 +790,38 @@ def _expand_inputs(inputs, user: Optional[str] = None): return expanded_inputs -def _read_config(config_file, user: Optional[str] = None): - config_args = {'inputs': None, - 'output': None, - 'exclude': None, - 'keep': -1, - 'ssh_host': None, - 'ssh_user': None, - 'ssh_keyfile': None, - 'remote_sudo': False, - 'numeric_ids': False} +class ConfigArgs(TypedDict): + """Values read from the configuration file""" + + inputs: Optional[List[str]] + output: Optional[str] + exclude: Optional[List[str]] + keep: int + ssh_host: Optional[str] + ssh_user: Optional[str] + ssh_keyfile: Optional[str] + remote_sudo: bool + numeric_ids: bool + + +def _get_bool(config: configparser.ConfigParser, key: str) -> bool: + # Empty values (as in the example config) count as false + if config.get('server', key, fallback='').strip() == '': + return False + + return config.getboolean('server', key) + + +def _read_config(config_file: str, user: Optional[str] = None) -> ConfigArgs: + config_args: ConfigArgs = {'inputs': None, + 'output': None, + 'exclude': None, + 'keep': -1, + 'ssh_host': None, + 'ssh_user': None, + 'ssh_keyfile': None, + 'remote_sudo': False, + 'numeric_ids': False} if not os.path.isfile(config_file): if user is not None: @@ -823,29 +845,15 @@ def _read_config(config_file, user: Optional[str] = None): section = 'default' inputs = config.get(section, 'inputs') - inputs = [i.strip() for i in inputs.split(',')] - inputs = _expand_inputs(inputs, user) - inputs = list(set(inputs)) - - config_args['inputs'] = inputs + config_args['inputs'] = list(set(_expand_inputs([i.strip() for i in inputs.split(',')], user))) # '~' is expanded later, since for remote backups it refers to the home on the server config_args['output'] = config.get(section, 'backup_dir') - try: - exclude = config.get(section, 'exclude') - exclude = [e.strip() for e in exclude.split(',') if e.strip() != ''] - except configparser.NoOptionError: - exclude = [] + exclude = config.get(section, 'exclude', fallback='') + config_args['exclude'] = [e.strip() for e in exclude.split(',') if e.strip() != ''] - config_args['exclude'] = exclude - - try: - keep = config.getint(section, 'keep') - except configparser.NoOptionError: - keep = -1 - - config_args['keep'] = keep + config_args['keep'] = config.getint(section, 'keep', fallback=-1) # Read host and user separately, so that a missing one is reported instead of silently # disabling remote backup. Empty values count as not set @@ -854,12 +862,8 @@ def _read_config(config_file, user: Optional[str] = None): config_args['ssh_keyfile'] = config.get('server', 'ssh_keyfile', fallback='').strip() or None - # Empty values (as in the example config) count as false - for key in ['remote_sudo', 'numeric_ids']: - if config.get('server', key, fallback='').strip() == '': - config_args[key] = False - else: - config_args[key] = config.getboolean('server', key) + config_args['remote_sudo'] = _get_bool(config, 'remote_sudo') + config_args['numeric_ids'] = _get_bool(config, 'numeric_ids') return config_args