4949
5050
5151# typing ----------------------------------------------------------------------
52- from typing import Callable ,Dict ,TYPE_CHECKING
52+ from typing import Callable ,Dict ,Mapping , Sequence , TYPE_CHECKING
5353from typing import Any ,Iterator ,Union
5454
55- from git .types import Commit_ish ,PathLike
55+ from git .types import Commit_ish ,PathLike , TBD
5656
5757if TYPE_CHECKING :
5858from git .repo import Repo
@@ -227,7 +227,7 @@ def _config_parser(cls, repo: 'Repo',
227227
228228return SubmoduleConfigParser (fp_module ,read_only = read_only )
229229
230- def _clear_cache (self ):
230+ def _clear_cache (self )-> None :
231231# clear the possibly changed values
232232for name in self ._cache_attrs :
233233try :
@@ -247,7 +247,7 @@ def _sio_modules(cls, parent_commit: Commit_ish) -> BytesIO:
247247def _config_parser_constrained (self ,read_only :bool )-> SectionConstraint :
248248""":return: Config Parser constrained to our submodule in read or write mode"""
249249try :
250- pc = self .parent_commit
250+ pc : Union [ 'Commit_ish' , None ] = self .parent_commit
251251except ValueError :
252252pc = None
253253# end handle empty parent repository
@@ -256,10 +256,12 @@ def _config_parser_constrained(self, read_only: bool) -> SectionConstraint:
256256return SectionConstraint (parser ,sm_section (self .name ))
257257
258258@classmethod
259- def _module_abspath (cls ,parent_repo ,path ,name ) :
259+ def _module_abspath (cls ,parent_repo : 'Repo' ,path : PathLike ,name : str ) -> PathLike :
260260if cls ._need_gitfile_submodules (parent_repo .git ):
261261return osp .join (parent_repo .git_dir ,'modules' ,name )
262- return osp .join (parent_repo .working_tree_dir ,path )
262+ if parent_repo .working_tree_dir :
263+ return osp .join (parent_repo .working_tree_dir ,path )
264+ raise NotADirectoryError ()
263265# end
264266
265267@classmethod
@@ -287,15 +289,15 @@ def _clone_repo(cls, repo, url, path, name, **kwargs):
287289return clone
288290
289291@classmethod
290- def _to_relative_path (cls ,parent_repo ,path ) :
292+ def _to_relative_path (cls ,parent_repo : 'Repo' ,path : PathLike ) -> PathLike :
291293""":return: a path guaranteed to be relative to the given parent - repository
292294 :raise ValueError: if path is not contained in the parent repository's working tree"""
293295path = to_native_path_linux (path )
294296if path .endswith ('/' ):
295297path = path [:- 1 ]
296298# END handle trailing slash
297299
298- if osp .isabs (path ):
300+ if osp .isabs (path )and parent_repo . working_tree_dir :
299301working_tree_linux = to_native_path_linux (parent_repo .working_tree_dir )
300302if not path .startswith (working_tree_linux ):
301303raise ValueError ("Submodule checkout path '%s' needs to be within the parents repository at '%s'"
@@ -309,7 +311,7 @@ def _to_relative_path(cls, parent_repo, path):
309311return path
310312
311313@classmethod
312- def _write_git_file_and_module_config (cls ,working_tree_dir ,module_abspath ) :
314+ def _write_git_file_and_module_config (cls ,working_tree_dir : PathLike ,module_abspath : PathLike ) -> None :
313315"""Writes a .git file containing a(preferably) relative path to the actual git module repository.
314316 It is an error if the module_abspath cannot be made into a relative path, relative to the working_tree_dir
315317 :note: will overwrite existing files !
@@ -336,7 +338,8 @@ def _write_git_file_and_module_config(cls, working_tree_dir, module_abspath):
336338
337339@classmethod
338340def add (cls ,repo :'Repo' ,name :str ,path :PathLike ,url :Union [str ,None ]= None ,
339- branch = None ,no_checkout :bool = False ,depth = None ,env = None ,clone_multi_options = None
341+ branch :Union [str ,None ]= None ,no_checkout :bool = False ,depth :Union [int ,None ]= None ,
342+ env :Mapping [str ,str ]= None ,clone_multi_options :Union [Sequence [TBD ],None ]= None
340343 )-> 'Submodule' :
341344"""Add a new submodule to the given repository. This will alter the index
342345 as well as the .gitmodules file, but will not create a new commit.
@@ -415,7 +418,8 @@ def add(cls, repo: 'Repo', name: str, path: PathLike, url: Union[str, None] = No
415418# END check url
416419# END verify urls match
417420
418- mrepo = None
421+ # mrepo: Union[Repo, None] = None
422+
419423if url is None :
420424if not has_module :
421425raise ValueError ("A URL was not given and a repository did not exist at %s" % path )
@@ -428,7 +432,7 @@ def add(cls, repo: 'Repo', name: str, path: PathLike, url: Union[str, None] = No
428432url = urls [0 ]
429433else :
430434# clone new repo
431- kwargs :Dict [str ,Union [bool ,int ]]= {'n' :no_checkout }
435+ kwargs :Dict [str ,Union [bool ,int , Sequence [ TBD ] ]]= {'n' :no_checkout }
432436if not branch_is_default :
433437kwargs ['b' ]= br .name
434438# END setup checkout-branch
@@ -452,6 +456,8 @@ def add(cls, repo: 'Repo', name: str, path: PathLike, url: Union[str, None] = No
452456# otherwise there is a '-' character in front of the submodule listing
453457# a38efa84daef914e4de58d1905a500d8d14aaf45 mymodule (v0.9.0-1-ga38efa8)
454458# -a38efa84daef914e4de58d1905a500d8d14aaf45 submodules/intermediate/one
459+ writer :Union [GitConfigParser ,SectionConstraint ]
460+
455461with sm .repo .config_writer ()as writer :
456462writer .set_value (sm_section (name ),'url' ,url )
457463
@@ -473,8 +479,10 @@ def add(cls, repo: 'Repo', name: str, path: PathLike, url: Union[str, None] = No
473479
474480return sm
475481
476- def update (self ,recursive = False ,init = True ,to_latest_revision = False ,progress = None ,dry_run = False ,
477- force = False ,keep_going = False ,env = None ,clone_multi_options = None ):
482+ def update (self ,recursive :bool = False ,init :bool = True ,to_latest_revision :bool = False ,
483+ progress :Union ['UpdateProgress' ,None ]= None ,dry_run :bool = False ,
484+ force :bool = False ,keep_going :bool = False ,env :Mapping [str ,str ]= None ,
485+ clone_multi_options :Union [Sequence [TBD ],None ]= None ):
478486"""Update the repository of this submodule to point to the checkout
479487 we point at with the binsha of this instance.
480488
@@ -581,6 +589,7 @@ def update(self, recursive=False, init=True, to_latest_revision=False, progress=
581589if not dry_run :
582590# see whether we have a valid branch to checkout
583591try :
592+ assert isinstance (mrepo ,Repo )
584593# find a remote which has our branch - we try to be flexible
585594remote_branch = find_first_remote_branch (mrepo .remotes ,self .branch_name )
586595local_branch = mkhead (mrepo ,self .branch_path )
@@ -641,7 +650,7 @@ def update(self, recursive=False, init=True, to_latest_revision=False, progress=
641650may_reset = True
642651if mrepo .head .commit .binsha != self .NULL_BIN_SHA :
643652base_commit = mrepo .merge_base (mrepo .head .commit ,hexsha )
644- if len (base_commit )== 0 or base_commit [0 ].hexsha == hexsha :
653+ if len (base_commit )== 0 or ( base_commit [0 ]is not None and base_commit [ 0 ] .hexsha == hexsha ) :
645654if force :
646655msg = "Will force checkout or reset on local branch that is possibly in the future of"
647656msg += "the commit it will be checked out to, effectively 'forgetting' new commits"
@@ -916,7 +925,7 @@ def remove(self, module: bool = True, force: bool = False,
916925import gc
917926gc .collect ()
918927try :
919- rmtree (wtd )
928+ rmtree (str ( wtd ) )
920929except Exception as ex :
921930if HIDE_WINDOWS_KNOWN_ERRORS :
922931raise SkipTest ("FIXME: fails with: PermissionError\n {}" .format (ex ))from ex
@@ -954,6 +963,8 @@ def remove(self, module: bool = True, force: bool = False,
954963
955964# now git config - need the config intact, otherwise we can't query
956965# information anymore
966+ writer :Union [GitConfigParser ,SectionConstraint ]
967+
957968with self .repo .config_writer ()as writer :
958969writer .remove_section (sm_section (self .name ))
959970
@@ -1067,13 +1078,14 @@ def rename(self, new_name: str) -> 'Submodule':
10671078destination_module_abspath = self ._module_abspath (self .repo ,self .path ,new_name )
10681079source_dir = mod .git_dir
10691080# Let's be sure the submodule name is not so obviously tied to a directory
1070- if destination_module_abspath .startswith (mod .git_dir ):
1081+ if str ( destination_module_abspath ) .startswith (str ( mod .git_dir ) ):
10711082tmp_dir = self ._module_abspath (self .repo ,self .path ,str (uuid .uuid4 ()))
10721083os .renames (source_dir ,tmp_dir )
10731084source_dir = tmp_dir
10741085# end handle self-containment
10751086os .renames (source_dir ,destination_module_abspath )
1076- self ._write_git_file_and_module_config (mod .working_tree_dir ,destination_module_abspath )
1087+ if mod .working_tree_dir :
1088+ self ._write_git_file_and_module_config (mod .working_tree_dir ,destination_module_abspath )
10771089# end move separate git repository
10781090
10791091return self
@@ -1150,34 +1162,34 @@ def branch(self):
11501162return mkhead (self .module (),self ._branch_path )
11511163
11521164@property
1153- def branch_path (self ):
1165+ def branch_path (self )-> PathLike :
11541166"""
11551167 :return: full(relative) path as string to the branch we would checkout
11561168 from the remote and track"""
11571169return self ._branch_path
11581170
11591171@property
1160- def branch_name (self ):
1172+ def branch_name (self )-> str :
11611173""":return: the name of the branch, which is the shortest possible branch name"""
11621174# use an instance method, for this we create a temporary Head instance
11631175# which uses a repository that is available at least ( it makes no difference )
11641176return git .Head (self .repo ,self ._branch_path ).name
11651177
11661178@property
1167- def url (self ):
1179+ def url (self )-> str :
11681180""":return: The url to the repository which our module - repository refers to"""
11691181return self ._url
11701182
11711183@property
1172- def parent_commit (self ):
1184+ def parent_commit (self )-> 'Commit_ish' :
11731185""":return: Commit instance with the tree containing the .gitmodules file
11741186 :note: will always point to the current head's commit if it was not set explicitly"""
11751187if self ._parent_commit is None :
11761188return self .repo .commit ()
11771189return self ._parent_commit
11781190
11791191@property
1180- def name (self ):
1192+ def name (self )-> str :
11811193""":return: The name of this submodule. It is used to identify it within the
11821194 .gitmodules file.
11831195 :note: by default, the name is the path at which to find the submodule, but