2929
3030import configparser as cp
3131
32+ from pathlib import Path
33+
3234# typing-------------------------------------------------------
3335
34- from typing import Any , Callable , List , Mapping , TYPE_CHECKING , Tuple , Union , overload
36+ from typing import Any , Callable , IO , List , Dict , Sequence , TYPE_CHECKING , Tuple , Union , cast , overload
3537
36- from git .types import Literal , Lit_config_levels , TBD
38+ from git .types import Literal , Lit_config_levels , PathLike , TBD
3739
3840if TYPE_CHECKING :
39- pass
41+ from git . repo . base import Repo
4042
4143# -------------------------------------------------------------
4244
5961class MetaParserBuilder (abc .ABCMeta ):
6062
6163 """Utlity class wrapping base-class methods into decorators that assure read-only properties"""
62- def __new__ (cls , name : str , bases : TBD , clsdict : Mapping [str , Any ]) -> TBD :
64+ def __new__ (cls , name : str , bases : TBD , clsdict : Dict [str , Any ]) -> TBD :
6365 """
6466 Equip all base-class methods with a needs_values decorator, and all non-const methods
6567 with a set_dirty_and_flush_changes decorator in addition to that."""
@@ -124,7 +126,7 @@ class SectionConstraint(object):
124126 _valid_attrs_ = ("get_value" , "set_value" , "get" , "set" , "getint" , "getfloat" , "getboolean" , "has_option" ,
125127 "remove_section" , "remove_option" , "options" )
126128
127- def __init__ (self , config : cp . ConfigParser , section : str ) -> None :
129+ def __init__ (self , config : 'GitConfigParser' , section : str ) -> None :
128130 self ._config = config
129131 self ._section_name = section
130132
@@ -145,7 +147,7 @@ def _call_config(self, method: str, *args: Any, **kwargs: Any) -> Any:
145147 return getattr (self ._config , method )(self ._section_name , * args , ** kwargs )
146148
147149 @property
148- def config (self ) -> cp . ConfigParser :
150+ def config (self ) -> 'GitConfigParser' :
149151 """return: Configparser instance we constrain"""
150152 return self ._config
151153
@@ -204,7 +206,7 @@ def get(self, key: str, default: Union[Any, None] = None) -> Union[Any, None]:
204206 def getall (self , key : str ) -> Any :
205207 return super (_OMD , self ).__getitem__ (key )
206208
207- def items (self ) -> List [Tuple [str , Any ]]:
209+ def items (self ) -> List [Tuple [str , Any ]]: # type: ignore ## mypy doesn't like overwriting supertype signitures
208210 """List of (key, last value for key)."""
209211 return [(k , self [k ]) for k in self ]
210212
@@ -271,7 +273,10 @@ class GitConfigParser(with_metaclass(MetaParserBuilder, cp.RawConfigParser, obje
271273 # list of RawConfigParser methods able to change the instance
272274 _mutating_methods_ = ("add_section" , "remove_section" , "remove_option" , "set" )
273275
274- def __init__ (self , file_or_files = None , read_only = True , merge_includes = True , config_level = None , repo = None ):
276+ def __init__ (self , file_or_files : Union [None , PathLike , IO , Sequence [Union [PathLike , IO ]]] = None ,
277+ read_only : bool = True , merge_includes : bool = True ,
278+ config_level : Union [Lit_config_levels , None ] = None ,
279+ repo : Union ['Repo' , None ] = None ) -> None :
275280 """Initialize a configuration reader to read the given file_or_files and to
276281 possibly allow changes to it by setting read_only False
277282
@@ -297,11 +302,13 @@ def __init__(self, file_or_files=None, read_only=True, merge_includes=True, conf
297302 self ._proxies = self ._dict ()
298303
299304 if file_or_files is not None :
300- self ._file_or_files = file_or_files
305+ self ._file_or_files = file_or_files # type: Union[PathLike, IO, Sequence[Union[PathLike, IO]]]
301306 else :
302307 if config_level is None :
303308 if read_only :
304- self ._file_or_files = [get_config_path (f ) for f in CONFIG_LEVELS if f != 'repository' ]
309+ self ._file_or_files = [get_config_path (f ) # type: ignore
310+ for f in CONFIG_LEVELS # Can type f properly when 3.5 dropped
311+ if f != 'repository' ]
305312 else :
306313 raise ValueError ("No configuration level or configuration files specified" )
307314 else :
@@ -312,20 +319,21 @@ def __init__(self, file_or_files=None, read_only=True, merge_includes=True, conf
312319 self ._is_initialized = False
313320 self ._merge_includes = merge_includes
314321 self ._repo = repo
315- self ._lock = None
322+ self ._lock = None # type: Union['LockFile', None]
316323 self ._acquire_lock ()
317324
318- def _acquire_lock (self ):
325+ def _acquire_lock (self ) -> None :
319326 if not self ._read_only :
320327 if not self ._lock :
321- if isinstance (self ._file_or_files , (tuple , list )):
328+ if isinstance (self ._file_or_files , (tuple , list , Sequence )):
322329 raise ValueError (
323330 "Write-ConfigParsers can operate on a single file only, multiple files have been passed" )
324331 # END single file check
325332
326- file_or_files = self ._file_or_files
327- if not isinstance (self ._file_or_files , str ):
328- file_or_files = self ._file_or_files .name
333+ if not isinstance (self ._file_or_files , (str , Path )): # cannot narrow by os._pathlike until 3.5 dropped
334+ file_or_files = cast (IO , self ._file_or_files ).name # type: PathLike
335+ else :
336+ file_or_files = self ._file_or_files
329337 # END get filename from handle/stream
330338 # initialize lock base - we want to write
331339 self ._lock = self .t_lock (file_or_files )
@@ -366,7 +374,8 @@ def release(self) -> None:
366374 # Usually when shutting down the interpreter, don'y know how to fix this
367375 pass
368376 finally :
369- self ._lock ._release_lock ()
377+ if self ._lock is not None :
378+ self ._lock ._release_lock ()
370379
371380 def optionxform (self , optionstr ):
372381 """Do not transform options in any way when writing"""
0 commit comments