55import string
66from configparser import RawConfigParser
77from itertools import chain
8+ from typing import IO
9+ from typing import Any
10+ from typing import Generator
811
912from .. import PROJECT_HOME
1013from .. import exceptions
1114from ..utils import cached_property
1215from ..utils import expand_path
16+ from ..vobject import Item
1317from .fetchparams import expand_fetch_params
1418from .utils import storage_class_from_config
1519
@@ -29,10 +33,10 @@ def validate_section_name(name, section_type):
2933 )
3034
3135
32- def _validate_general_section (general_config ):
36+ def _validate_general_section (general_config : dict [ str , str ] ):
3337 invalid = set (general_config ) - GENERAL_ALL
3438 missing = GENERAL_REQUIRED - set (general_config )
35- problems = []
39+ problems : list [ str ] = []
3640
3741 if invalid :
3842 problems .append (
@@ -92,17 +96,22 @@ def _validate_collections_param(collections):
9296
9397
9498class _ConfigReader :
95- def __init__ (self , f ):
96- self ._file = f
99+ def __init__ (self , f : IO [ Any ] ):
100+ self ._file : IO [ Any ] = f
97101 self ._parser = c = RawConfigParser ()
98102 c .read_file (f )
99- self ._seen_names = set ()
100-
101- self ._general = {}
102- self ._pairs = {}
103- self ._storages = {}
104-
105- def _parse_section (self , section_type , name , options ):
103+ self ._seen_names : set = set ()
104+
105+ self ._general : dict [str , str ] = {}
106+ self ._pairs : dict [str , dict [str , str ]] = {}
107+ self ._storages : dict [str , dict [str , str ]] = {}
108+
109+ def _parse_section (
110+ self ,
111+ section_type : str ,
112+ name : str ,
113+ options : dict [str , Any ]
114+ ) -> None :
106115 validate_section_name (name , section_type )
107116 if name in self ._seen_names :
108117 raise ValueError (f'Name "{ name } " already used.' )
@@ -119,7 +128,9 @@ def _parse_section(self, section_type, name, options):
119128 else :
120129 raise ValueError ("Unknown section type." )
121130
122- def parse (self ):
131+ def parse (
132+ self
133+ ) -> tuple [dict [str , str ], dict [str , dict [str , str ]], dict [str , dict [str , str ]]]:
123134 for section in self ._parser .sections ():
124135 if " " in section :
125136 section_type , name = section .split (" " , 1 )
@@ -145,7 +156,10 @@ def parse(self):
145156 return self ._general , self ._pairs , self ._storages
146157
147158
148- def _parse_options (items , section = None ):
159+ def _parse_options (
160+ items : list [tuple [str , str ]],
161+ section : str | None = None
162+ ) -> Generator [tuple [str , dict [str , str ]], None , None ]:
149163 for key , value in items :
150164 try :
151165 yield key , json .loads (value )
@@ -154,26 +168,31 @@ def _parse_options(items, section=None):
154168
155169
156170class Config :
157- def __init__ (self , general , pairs , storages ):
171+ def __init__ (
172+ self ,
173+ general : dict [str , str ],
174+ pairs : dict [str , dict [str , str ]],
175+ storages : dict [str , dict [str , str ]]
176+ ) -> None :
158177 self .general = general
159178 self .storages = storages
160179 for name , options in storages .items ():
161180 options ["instance_name" ] = name
162181
163- self .pairs = {}
182+ self .pairs : dict [ str , PairConfig ] = {}
164183 for name , options in pairs .items ():
165184 try :
166185 self .pairs [name ] = PairConfig (self , name , options )
167186 except ValueError as e :
168187 raise exceptions .UserError (f"Pair { name } : { e } " )
169188
170189 @classmethod
171- def from_fileobject (cls , f ):
190+ def from_fileobject (cls , f : IO [ Any ] ):
172191 reader = _ConfigReader (f )
173192 return cls (* reader .parse ())
174193
175194 @classmethod
176- def from_filename_or_environment (cls , fname = None ):
195+ def from_filename_or_environment (cls , fname : str | None = None ):
177196 if fname is None :
178197 fname = os .environ .get ("VDIRSYNCER_CONFIG" , None )
179198 if fname is None :
@@ -190,7 +209,7 @@ def from_filename_or_environment(cls, fname=None):
190209 except Exception as e :
191210 raise exceptions .UserError (f"Error during reading config { fname } : { e } " )
192211
193- def get_storage_args (self , storage_name ):
212+ def get_storage_args (self , storage_name : str ):
194213 try :
195214 args = self .storages [storage_name ]
196215 except KeyError :
@@ -211,13 +230,13 @@ def get_pair(self, pair_name: str) -> PairConfig:
211230
212231
213232class PairConfig :
214- def __init__ (self , full_config , name , options ):
215- self ._config = full_config
216- self .name = name
217- self .name_a = options .pop ("a" )
218- self .name_b = options .pop ("b" )
233+ def __init__ (self , full_config : Config , name : str , options : dict [ str , str ] ):
234+ self ._config : Config = full_config
235+ self .name : str = name
236+ self .name_a : str = options .pop ("a" )
237+ self .name_b : str = options .pop ("b" )
219238
220- self ._partial_sync = options .pop ("partial_sync" , None )
239+ self ._partial_sync : str | None = options .pop ("partial_sync" , None )
221240 self .metadata = options .pop ("metadata" , None ) or ()
222241
223242 self .conflict_resolution = self ._process_conflict_resolution_param (
@@ -238,7 +257,10 @@ def __init__(self, full_config, name, options):
238257 if options :
239258 raise ValueError ("Unknown options: {}" .format (", " .join (options )))
240259
241- def _process_conflict_resolution_param (self , conflict_resolution ):
260+ def _process_conflict_resolution_param (
261+ self ,
262+ conflict_resolution : str | list [str ] | None
263+ ):
242264 if conflict_resolution in (None , "a wins" , "b wins" ):
243265 return conflict_resolution
244266 elif (
@@ -302,10 +324,10 @@ def partial_sync(self):
302324
303325
304326class CollectionConfig :
305- def __init__ (self , pair , name , config_a , config_b ):
327+ def __init__ (self , pair , name : str , config_a , config_b ):
306328 self .pair = pair
307329 self ._config = pair ._config
308- self .name = name
330+ self .name : str = name
309331 self .config_a = config_a
310332 self .config_b = config_b
311333
@@ -314,7 +336,14 @@ def __init__(self, pair, name, config_a, config_b):
314336load_config = Config .from_filename_or_environment
315337
316338
317- def _resolve_conflict_via_command (a , b , command , a_name , b_name , _check_call = None ):
339+ def _resolve_conflict_via_command (
340+ a ,
341+ b ,
342+ command ,
343+ a_name ,
344+ b_name ,
345+ _check_call = None
346+ ) -> Item :
318347 import shutil
319348 import tempfile
320349
0 commit comments