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 :
5858 from git .repo import Repo
@@ -227,7 +227,7 @@ def _config_parser(cls, repo: 'Repo',
227227
228228 return 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
232232 for name in self ._cache_attrs :
233233 try :
@@ -247,7 +247,7 @@ def _sio_modules(cls, parent_commit: Commit_ish) -> BytesIO:
247247 def _config_parser_constrained (self , read_only : bool ) -> SectionConstraint :
248248 """:return: Config Parser constrained to our submodule in read or write mode"""
249249 try :
250- pc = self .parent_commit
250+ pc : Union [ 'Commit_ish' , None ] = self .parent_commit
251251 except ValueError :
252252 pc = None
253253 # end handle empty parent repository
@@ -256,10 +256,12 @@ def _config_parser_constrained(self, read_only: bool) -> SectionConstraint:
256256 return 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 :
260260 if cls ._need_gitfile_submodules (parent_repo .git ):
261261 return 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):
287289 return 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"""
293295 path = to_native_path_linux (path )
294296 if path .endswith ('/' ):
295297 path = path [:- 1 ]
296298 # END handle trailing slash
297299
298- if osp .isabs (path ):
300+ if osp .isabs (path ) and parent_repo . working_tree_dir :
299301 working_tree_linux = to_native_path_linux (parent_repo .working_tree_dir )
300302 if not path .startswith (working_tree_linux ):
301303 raise 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):
309311 return 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
338340 def 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+
419423 if url is None :
420424 if not has_module :
421425 raise 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
428432 url = urls [0 ]
429433 else :
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 }
432436 if not branch_is_default :
433437 kwargs ['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+
455461 with sm .repo .config_writer () as writer :
456462 writer .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
474480 return 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=
581589 if not dry_run :
582590 # see whether we have a valid branch to checkout
583591 try :
592+ assert isinstance (mrepo , Repo )
584593 # find a remote which has our branch - we try to be flexible
585594 remote_branch = find_first_remote_branch (mrepo .remotes , self .branch_name )
586595 local_branch = mkhead (mrepo , self .branch_path )
@@ -641,7 +650,7 @@ def update(self, recursive=False, init=True, to_latest_revision=False, progress=
641650 may_reset = True
642651 if mrepo .head .commit .binsha != self .NULL_BIN_SHA :
643652 base_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 ) :
645654 if force :
646655 msg = "Will force checkout or reset on local branch that is possibly in the future of"
647656 msg += "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,
916925 import gc
917926 gc .collect ()
918927 try :
919- rmtree (wtd )
928+ rmtree (str ( wtd ) )
920929 except Exception as ex :
921930 if HIDE_WINDOWS_KNOWN_ERRORS :
922931 raise 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+
957968 with self .repo .config_writer () as writer :
958969 writer .remove_section (sm_section (self .name ))
959970
@@ -1067,13 +1078,14 @@ def rename(self, new_name: str) -> 'Submodule':
10671078 destination_module_abspath = self ._module_abspath (self .repo , self .path , new_name )
10681079 source_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 ) ):
10711082 tmp_dir = self ._module_abspath (self .repo , self .path , str (uuid .uuid4 ()))
10721083 os .renames (source_dir , tmp_dir )
10731084 source_dir = tmp_dir
10741085 # end handle self-containment
10751086 os .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
10791091 return self
@@ -1150,34 +1162,34 @@ def branch(self):
11501162 return 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"""
11571169 return 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 )
11641176 return 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"""
11691181 return 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"""
11751187 if self ._parent_commit is None :
11761188 return self .repo .commit ()
11771189 return 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
0 commit comments