mirror of
https://github.com/samsonjs/vdirsyncer.git
synced 2026-04-27 14:57:41 +00:00
Add Typing annotation to cli/config.py
This commit is contained in:
parent
08616abbb5
commit
ef8e8980d1
1 changed files with 55 additions and 26 deletions
|
|
@ -5,11 +5,15 @@ import os
|
||||||
import string
|
import string
|
||||||
from configparser import RawConfigParser
|
from configparser import RawConfigParser
|
||||||
from itertools import chain
|
from itertools import chain
|
||||||
|
from typing import IO
|
||||||
|
from typing import Any
|
||||||
|
from typing import Generator
|
||||||
|
|
||||||
from .. import PROJECT_HOME
|
from .. import PROJECT_HOME
|
||||||
from .. import exceptions
|
from .. import exceptions
|
||||||
from ..utils import cached_property
|
from ..utils import cached_property
|
||||||
from ..utils import expand_path
|
from ..utils import expand_path
|
||||||
|
from ..vobject import Item
|
||||||
from .fetchparams import expand_fetch_params
|
from .fetchparams import expand_fetch_params
|
||||||
from .utils import storage_class_from_config
|
from .utils import storage_class_from_config
|
||||||
|
|
||||||
|
|
@ -29,10 +33,10 @@ def validate_section_name(name, section_type):
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
def _validate_general_section(general_config):
|
def _validate_general_section(general_config: dict[str, str]):
|
||||||
invalid = set(general_config) - GENERAL_ALL
|
invalid = set(general_config) - GENERAL_ALL
|
||||||
missing = GENERAL_REQUIRED - set(general_config)
|
missing = GENERAL_REQUIRED - set(general_config)
|
||||||
problems = []
|
problems: list[str] = []
|
||||||
|
|
||||||
if invalid:
|
if invalid:
|
||||||
problems.append(
|
problems.append(
|
||||||
|
|
@ -92,17 +96,22 @@ def _validate_collections_param(collections):
|
||||||
|
|
||||||
|
|
||||||
class _ConfigReader:
|
class _ConfigReader:
|
||||||
def __init__(self, f):
|
def __init__(self, f: IO[Any]):
|
||||||
self._file = f
|
self._file: IO[Any] = f
|
||||||
self._parser = c = RawConfigParser()
|
self._parser = c = RawConfigParser()
|
||||||
c.read_file(f)
|
c.read_file(f)
|
||||||
self._seen_names = set()
|
self._seen_names: set = set()
|
||||||
|
|
||||||
self._general = {}
|
self._general: dict[str, str] = {}
|
||||||
self._pairs = {}
|
self._pairs: dict[str, dict[str, str]] = {}
|
||||||
self._storages = {}
|
self._storages: dict[str, dict[str, str]] = {}
|
||||||
|
|
||||||
def _parse_section(self, section_type, name, options):
|
def _parse_section(
|
||||||
|
self,
|
||||||
|
section_type: str,
|
||||||
|
name: str,
|
||||||
|
options: dict[str, Any]
|
||||||
|
) -> None:
|
||||||
validate_section_name(name, section_type)
|
validate_section_name(name, section_type)
|
||||||
if name in self._seen_names:
|
if name in self._seen_names:
|
||||||
raise ValueError(f'Name "{name}" already used.')
|
raise ValueError(f'Name "{name}" already used.')
|
||||||
|
|
@ -119,7 +128,9 @@ class _ConfigReader:
|
||||||
else:
|
else:
|
||||||
raise ValueError("Unknown section type.")
|
raise ValueError("Unknown section type.")
|
||||||
|
|
||||||
def parse(self):
|
def parse(
|
||||||
|
self
|
||||||
|
) -> tuple[dict[str, str], dict[str, dict[str, str]], dict[str, dict[str, str]]]:
|
||||||
for section in self._parser.sections():
|
for section in self._parser.sections():
|
||||||
if " " in section:
|
if " " in section:
|
||||||
section_type, name = section.split(" ", 1)
|
section_type, name = section.split(" ", 1)
|
||||||
|
|
@ -145,7 +156,10 @@ class _ConfigReader:
|
||||||
return self._general, self._pairs, self._storages
|
return self._general, self._pairs, self._storages
|
||||||
|
|
||||||
|
|
||||||
def _parse_options(items, section=None):
|
def _parse_options(
|
||||||
|
items: list[tuple[str, str]],
|
||||||
|
section: str | None = None
|
||||||
|
) -> Generator[tuple[str, dict[str, str]], None, None]:
|
||||||
for key, value in items:
|
for key, value in items:
|
||||||
try:
|
try:
|
||||||
yield key, json.loads(value)
|
yield key, json.loads(value)
|
||||||
|
|
@ -154,13 +168,18 @@ def _parse_options(items, section=None):
|
||||||
|
|
||||||
|
|
||||||
class Config:
|
class Config:
|
||||||
def __init__(self, general, pairs, storages):
|
def __init__(
|
||||||
|
self,
|
||||||
|
general: dict[str, str],
|
||||||
|
pairs: dict[str, dict[str, str]],
|
||||||
|
storages: dict[str, dict[str, str]]
|
||||||
|
) -> None:
|
||||||
self.general = general
|
self.general = general
|
||||||
self.storages = storages
|
self.storages = storages
|
||||||
for name, options in storages.items():
|
for name, options in storages.items():
|
||||||
options["instance_name"] = name
|
options["instance_name"] = name
|
||||||
|
|
||||||
self.pairs = {}
|
self.pairs: dict[str, PairConfig] = {}
|
||||||
for name, options in pairs.items():
|
for name, options in pairs.items():
|
||||||
try:
|
try:
|
||||||
self.pairs[name] = PairConfig(self, name, options)
|
self.pairs[name] = PairConfig(self, name, options)
|
||||||
|
|
@ -168,12 +187,12 @@ class Config:
|
||||||
raise exceptions.UserError(f"Pair {name}: {e}")
|
raise exceptions.UserError(f"Pair {name}: {e}")
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def from_fileobject(cls, f):
|
def from_fileobject(cls, f: IO[Any]):
|
||||||
reader = _ConfigReader(f)
|
reader = _ConfigReader(f)
|
||||||
return cls(*reader.parse())
|
return cls(*reader.parse())
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def from_filename_or_environment(cls, fname=None):
|
def from_filename_or_environment(cls, fname: str | None = None):
|
||||||
if fname is None:
|
if fname is None:
|
||||||
fname = os.environ.get("VDIRSYNCER_CONFIG", None)
|
fname = os.environ.get("VDIRSYNCER_CONFIG", None)
|
||||||
if fname is None:
|
if fname is None:
|
||||||
|
|
@ -190,7 +209,7 @@ class Config:
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
raise exceptions.UserError(f"Error during reading config {fname}: {e}")
|
raise exceptions.UserError(f"Error during reading config {fname}: {e}")
|
||||||
|
|
||||||
def get_storage_args(self, storage_name):
|
def get_storage_args(self, storage_name: str):
|
||||||
try:
|
try:
|
||||||
args = self.storages[storage_name]
|
args = self.storages[storage_name]
|
||||||
except KeyError:
|
except KeyError:
|
||||||
|
|
@ -211,13 +230,13 @@ class Config:
|
||||||
|
|
||||||
|
|
||||||
class PairConfig:
|
class PairConfig:
|
||||||
def __init__(self, full_config, name, options):
|
def __init__(self, full_config: Config, name: str, options: dict[str, str]):
|
||||||
self._config = full_config
|
self._config: Config = full_config
|
||||||
self.name = name
|
self.name: str = name
|
||||||
self.name_a = options.pop("a")
|
self.name_a: str = options.pop("a")
|
||||||
self.name_b = options.pop("b")
|
self.name_b: str = options.pop("b")
|
||||||
|
|
||||||
self._partial_sync = options.pop("partial_sync", None)
|
self._partial_sync: str | None = options.pop("partial_sync", None)
|
||||||
self.metadata = options.pop("metadata", None) or ()
|
self.metadata = options.pop("metadata", None) or ()
|
||||||
|
|
||||||
self.conflict_resolution = self._process_conflict_resolution_param(
|
self.conflict_resolution = self._process_conflict_resolution_param(
|
||||||
|
|
@ -238,7 +257,10 @@ class PairConfig:
|
||||||
if options:
|
if options:
|
||||||
raise ValueError("Unknown options: {}".format(", ".join(options)))
|
raise ValueError("Unknown options: {}".format(", ".join(options)))
|
||||||
|
|
||||||
def _process_conflict_resolution_param(self, conflict_resolution):
|
def _process_conflict_resolution_param(
|
||||||
|
self,
|
||||||
|
conflict_resolution: str | list[str] | None
|
||||||
|
):
|
||||||
if conflict_resolution in (None, "a wins", "b wins"):
|
if conflict_resolution in (None, "a wins", "b wins"):
|
||||||
return conflict_resolution
|
return conflict_resolution
|
||||||
elif (
|
elif (
|
||||||
|
|
@ -302,10 +324,10 @@ class PairConfig:
|
||||||
|
|
||||||
|
|
||||||
class CollectionConfig:
|
class CollectionConfig:
|
||||||
def __init__(self, pair, name, config_a, config_b):
|
def __init__(self, pair, name: str, config_a, config_b):
|
||||||
self.pair = pair
|
self.pair = pair
|
||||||
self._config = pair._config
|
self._config = pair._config
|
||||||
self.name = name
|
self.name: str = name
|
||||||
self.config_a = config_a
|
self.config_a = config_a
|
||||||
self.config_b = config_b
|
self.config_b = config_b
|
||||||
|
|
||||||
|
|
@ -314,7 +336,14 @@ class CollectionConfig:
|
||||||
load_config = Config.from_filename_or_environment
|
load_config = Config.from_filename_or_environment
|
||||||
|
|
||||||
|
|
||||||
def _resolve_conflict_via_command(a, b, command, a_name, b_name, _check_call=None):
|
def _resolve_conflict_via_command(
|
||||||
|
a,
|
||||||
|
b,
|
||||||
|
command,
|
||||||
|
a_name,
|
||||||
|
b_name,
|
||||||
|
_check_call=None
|
||||||
|
) -> Item:
|
||||||
import shutil
|
import shutil
|
||||||
import tempfile
|
import tempfile
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue