Skip to content

Commit 94c2ae4

Browse files
committed
Readd submodule.base.py types
1 parent 215abfd commit 94c2ae4

File tree

2 files changed

+54
-39
lines changed

2 files changed

+54
-39
lines changed

‎git/diff.py

+3-2
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,8 @@
2828

2929

3030
def is_change_type(inp: str) -> TypeGuard[Lit_change_type]:
31-
return inp in ['A', 'D', 'C', 'M', 'R', 'T']
31+
return True
32+
# return inp in ['A', 'D', 'C', 'M', 'R', 'T']
3233

3334
# ------------------------------------------------------------------------
3435

@@ -511,7 +512,7 @@ def _handle_diff_line(lines_bytes: bytes, repo: 'Repo', index: DiffIndex) -> Non
511512
# Change type can be R100
512513
# R: status letter
513514
# 100: score (in case of copy and rename)
514-
assert is_change_type(_change_type[0])
515+
assert is_change_type(_change_type[0]), f"Unexpected value for change_type received: {_change_type[0]}"
515516
change_type: Lit_change_type = _change_type[0]
516517
score_str = ''.join(_change_type[1:])
517518
score = int(score_str) if score_str.isdigit() else None

‎git/objects/submodule/base.py

+51-37
Original file line numberDiff line numberDiff line change
@@ -47,15 +47,16 @@
4747
find_first_remote_branch
4848
)
4949

50+
from git.repo import Repo
5051

5152
# typing ----------------------------------------------------------------------
52-
from typing import Dict, TYPE_CHECKING
53+
from typing import Callable, Dict, Mapping, Sequence, TYPE_CHECKING
5354
from typing import Any, Iterator, Union
5455

55-
from git.types import Commit_ish, PathLike
56+
from git.types import Commit_ish, PathLike, TBD
5657

5758
if TYPE_CHECKING:
58-
from git.repo import Repo
59+
from git.index import IndexFile
5960

6061

6162
# -----------------------------------------------------------------------------
@@ -131,14 +132,14 @@ def __init__(self, repo: 'Repo', binsha: bytes,
131132
if url is not None:
132133
self._url = url
133134
if branch_path is not None:
134-
assert isinstance(branch_path, str)
135+
# assert isinstance(branch_path, str)
135136
self._branch_path = branch_path
136137
if name is not None:
137138
self._name = name
138139

139140
def _set_cache_(self, attr: str) -> None:
140141
if attr in ('path', '_url', '_branch_path'):
141-
reader = self.config_reader()
142+
reader: SectionConstraint = self.config_reader()
142143
# default submodule values
143144
try:
144145
self.path = reader.get('path')
@@ -226,7 +227,7 @@ def _config_parser(cls, repo: 'Repo',
226227

227228
return SubmoduleConfigParser(fp_module, read_only=read_only)
228229

229-
def _clear_cache(self):
230+
def _clear_cache(self) -> None:
230231
# clear the possibly changed values
231232
for name in self._cache_attrs:
232233
try:
@@ -246,7 +247,7 @@ def _sio_modules(cls, parent_commit: Commit_ish) -> BytesIO:
246247
def _config_parser_constrained(self, read_only: bool) -> SectionConstraint:
247248
""":return: Config Parser constrained to our submodule in read or write mode"""
248249
try:
249-
pc = self.parent_commit
250+
pc: Union['Commit_ish', None] = self.parent_commit
250251
except ValueError:
251252
pc = None
252253
# end handle empty parent repository
@@ -255,10 +256,12 @@ def _config_parser_constrained(self, read_only: bool) -> SectionConstraint:
255256
return SectionConstraint(parser, sm_section(self.name))
256257

257258
@classmethod
258-
def _module_abspath(cls, parent_repo, path, name):
259+
def _module_abspath(cls, parent_repo: 'Repo', path: PathLike, name: str) -> PathLike:
259260
if cls._need_gitfile_submodules(parent_repo.git):
260261
return osp.join(parent_repo.git_dir, 'modules', name)
261-
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()
262265
# end
263266

264267
@classmethod
@@ -286,15 +289,15 @@ def _clone_repo(cls, repo, url, path, name, **kwargs):
286289
return clone
287290

288291
@classmethod
289-
def _to_relative_path(cls, parent_repo, path):
292+
def _to_relative_path(cls, parent_repo: 'Repo', path: PathLike) -> PathLike:
290293
""":return: a path guaranteed to be relative to the given parent - repository
291294
:raise ValueError: if path is not contained in the parent repository's working tree"""
292295
path = to_native_path_linux(path)
293296
if path.endswith('/'):
294297
path = path[:-1]
295298
# END handle trailing slash
296299

297-
if osp.isabs(path):
300+
if osp.isabs(path) and parent_repo.working_tree_dir:
298301
working_tree_linux = to_native_path_linux(parent_repo.working_tree_dir)
299302
if not path.startswith(working_tree_linux):
300303
raise ValueError("Submodule checkout path '%s' needs to be within the parents repository at '%s'"
@@ -308,7 +311,7 @@ def _to_relative_path(cls, parent_repo, path):
308311
return path
309312

310313
@classmethod
311-
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:
312315
"""Writes a .git file containing a(preferably) relative path to the actual git module repository.
313316
It is an error if the module_abspath cannot be made into a relative path, relative to the working_tree_dir
314317
:note: will overwrite existing files !
@@ -335,7 +338,8 @@ def _write_git_file_and_module_config(cls, working_tree_dir, module_abspath):
335338

336339
@classmethod
337340
def add(cls, repo: 'Repo', name: str, path: PathLike, url: Union[str, None] = None,
338-
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
339343
) -> 'Submodule':
340344
"""Add a new submodule to the given repository. This will alter the index
341345
as well as the .gitmodules file, but will not create a new commit.
@@ -391,7 +395,7 @@ def add(cls, repo: 'Repo', name: str, path: PathLike, url: Union[str, None] = No
391395
if sm.exists():
392396
# reretrieve submodule from tree
393397
try:
394-
sm = repo.head.commit.tree[path] # type: ignore
398+
sm = repo.head.commit.tree[str(path)]
395399
sm._name = name
396400
return sm
397401
except KeyError:
@@ -414,7 +418,8 @@ def add(cls, repo: 'Repo', name: str, path: PathLike, url: Union[str, None] = No
414418
# END check url
415419
# END verify urls match
416420

417-
mrepo = None
421+
mrepo: Union[Repo, None] = None
422+
418423
if url is None:
419424
if not has_module:
420425
raise ValueError("A URL was not given and a repository did not exist at %s" % path)
@@ -427,7 +432,7 @@ def add(cls, repo: 'Repo', name: str, path: PathLike, url: Union[str, None] = No
427432
url = urls[0]
428433
else:
429434
# clone new repo
430-
kwargs: Dict[str, Union[bool, int]] = {'n': no_checkout}
435+
kwargs: Dict[str, Union[bool, int, Sequence[TBD]]] = {'n': no_checkout}
431436
if not branch_is_default:
432437
kwargs['b'] = br.name
433438
# END setup checkout-branch
@@ -451,6 +456,8 @@ def add(cls, repo: 'Repo', name: str, path: PathLike, url: Union[str, None] = No
451456
# otherwise there is a '-' character in front of the submodule listing
452457
# a38efa84daef914e4de58d1905a500d8d14aaf45 mymodule (v0.9.0-1-ga38efa8)
453458
# -a38efa84daef914e4de58d1905a500d8d14aaf45 submodules/intermediate/one
459+
writer: Union[GitConfigParser, SectionConstraint]
460+
454461
with sm.repo.config_writer() as writer:
455462
writer.set_value(sm_section(name), 'url', url)
456463

@@ -467,13 +474,15 @@ def add(cls, repo: 'Repo', name: str, path: PathLike, url: Union[str, None] = No
467474
sm._branch_path = br.path
468475

469476
# we deliberately assume that our head matches our index !
470-
sm.binsha = mrepo.head.commit.binsha
477+
sm.binsha = mrepo.head.commit.binsha # type: ignore
471478
index.add([sm], write=True)
472479

473480
return sm
474481

475-
def update(self, recursive=False, init=True, to_latest_revision=False, progress=None, dry_run=False,
476-
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):
477486
"""Update the repository of this submodule to point to the checkout
478487
we point at with the binsha of this instance.
479488
@@ -580,6 +589,7 @@ def update(self, recursive=False, init=True, to_latest_revision=False, progress=
580589
if not dry_run:
581590
# see whether we have a valid branch to checkout
582591
try:
592+
assert isinstance(mrepo, Repo)
583593
# find a remote which has our branch - we try to be flexible
584594
remote_branch = find_first_remote_branch(mrepo.remotes, self.branch_name)
585595
local_branch = mkhead(mrepo, self.branch_path)
@@ -640,7 +650,7 @@ def update(self, recursive=False, init=True, to_latest_revision=False, progress=
640650
may_reset = True
641651
if mrepo.head.commit.binsha != self.NULL_BIN_SHA:
642652
base_commit = mrepo.merge_base(mrepo.head.commit, hexsha)
643-
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):
644654
if force:
645655
msg = "Will force checkout or reset on local branch that is possibly in the future of"
646656
msg += "the commit it will be checked out to, effectively 'forgetting' new commits"
@@ -807,7 +817,8 @@ def move(self, module_path, configuration=True, module=True):
807817
return self
808818

809819
@unbare_repo
810-
def remove(self, module=True, force=False, configuration=True, dry_run=False):
820+
def remove(self, module: bool = True, force: bool = False,
821+
configuration: bool = True, dry_run: bool = False) -> 'Submodule':
811822
"""Remove this submodule from the repository. This will remove our entry
812823
from the .gitmodules file and the entry in the .git / config file.
813824
@@ -861,7 +872,7 @@ def remove(self, module=True, force=False, configuration=True, dry_run=False):
861872
# TODO: If we run into permission problems, we have a highly inconsistent
862873
# state. Delete the .git folders last, start with the submodules first
863874
mp = self.abspath
864-
method = None
875+
method: Union[None, Callable[[PathLike], None]] = None
865876
if osp.islink(mp):
866877
method = os.remove
867878
elif osp.isdir(mp):
@@ -914,7 +925,7 @@ def remove(self, module=True, force=False, configuration=True, dry_run=False):
914925
import gc
915926
gc.collect()
916927
try:
917-
rmtree(wtd)
928+
rmtree(str(wtd))
918929
except Exception as ex:
919930
if HIDE_WINDOWS_KNOWN_ERRORS:
920931
raise SkipTest("FIXME: fails with: PermissionError\n {}".format(ex)) from ex
@@ -928,7 +939,7 @@ def remove(self, module=True, force=False, configuration=True, dry_run=False):
928939
rmtree(git_dir)
929940
except Exception as ex:
930941
if HIDE_WINDOWS_KNOWN_ERRORS:
931-
raise SkipTest("FIXME: fails with: PermissionError\n %s", ex) from ex
942+
raise SkipTest(f"FIXME: fails with: PermissionError\n {ex}") from ex
932943
else:
933944
raise
934945
# end handle separate bare repository
@@ -952,6 +963,8 @@ def remove(self, module=True, force=False, configuration=True, dry_run=False):
952963

953964
# now git config - need the config intact, otherwise we can't query
954965
# information anymore
966+
writer: Union[GitConfigParser, SectionConstraint]
967+
955968
with self.repo.config_writer() as writer:
956969
writer.remove_section(sm_section(self.name))
957970

@@ -961,7 +974,7 @@ def remove(self, module=True, force=False, configuration=True, dry_run=False):
961974

962975
return self
963976

964-
def set_parent_commit(self, commit: Union[Commit_ish, None], check=True):
977+
def set_parent_commit(self, commit: Union[Commit_ish, None], check: bool = True) -> 'Submodule':
965978
"""Set this instance to use the given commit whose tree is supposed to
966979
contain the .gitmodules blob.
967980
@@ -1009,7 +1022,7 @@ def set_parent_commit(self, commit: Union[Commit_ish, None], check=True):
10091022
return self
10101023

10111024
@unbare_repo
1012-
def config_writer(self, index=None, write=True):
1025+
def config_writer(self, index: Union['IndexFile', None] = None, write: bool = True) -> SectionConstraint:
10131026
""":return: a config writer instance allowing you to read and write the data
10141027
belonging to this submodule into the .gitmodules file.
10151028
@@ -1030,7 +1043,7 @@ def config_writer(self, index=None, write=True):
10301043
return writer
10311044

10321045
@unbare_repo
1033-
def rename(self, new_name):
1046+
def rename(self, new_name: str) -> 'Submodule':
10341047
"""Rename this submodule
10351048
:note: This method takes care of renaming the submodule in various places, such as
10361049
@@ -1065,13 +1078,14 @@ def rename(self, new_name):
10651078
destination_module_abspath = self._module_abspath(self.repo, self.path, new_name)
10661079
source_dir = mod.git_dir
10671080
# Let's be sure the submodule name is not so obviously tied to a directory
1068-
if destination_module_abspath.startswith(mod.git_dir):
1081+
if str(destination_module_abspath).startswith(str(mod.git_dir)):
10691082
tmp_dir = self._module_abspath(self.repo, self.path, str(uuid.uuid4()))
10701083
os.renames(source_dir, tmp_dir)
10711084
source_dir = tmp_dir
10721085
# end handle self-containment
10731086
os.renames(source_dir, destination_module_abspath)
1074-
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)
10751089
# end move separate git repository
10761090

10771091
return self
@@ -1081,7 +1095,7 @@ def rename(self, new_name):
10811095
#{ Query Interface
10821096

10831097
@unbare_repo
1084-
def module(self):
1098+
def module(self) -> 'Repo':
10851099
""":return: Repo instance initialized from the repository at our submodule path
10861100
:raise InvalidGitRepositoryError: if a repository was not available. This could
10871101
also mean that it was not yet initialized"""
@@ -1098,7 +1112,7 @@ def module(self):
10981112
raise InvalidGitRepositoryError("Repository at %r was not yet checked out" % module_checkout_abspath)
10991113
# END handle exceptions
11001114

1101-
def module_exists(self):
1115+
def module_exists(self) -> bool:
11021116
""":return: True if our module exists and is a valid git repository. See module() method"""
11031117
try:
11041118
self.module()
@@ -1107,7 +1121,7 @@ def module_exists(self):
11071121
return False
11081122
# END handle exception
11091123

1110-
def exists(self):
1124+
def exists(self) -> bool:
11111125
"""
11121126
:return: True if the submodule exists, False otherwise. Please note that
11131127
a submodule may exist ( in the .gitmodules file) even though its module
@@ -1148,34 +1162,34 @@ def branch(self):
11481162
return mkhead(self.module(), self._branch_path)
11491163

11501164
@property
1151-
def branch_path(self):
1165+
def branch_path(self) -> PathLike:
11521166
"""
11531167
:return: full(relative) path as string to the branch we would checkout
11541168
from the remote and track"""
11551169
return self._branch_path
11561170

11571171
@property
1158-
def branch_name(self):
1172+
def branch_name(self) -> str:
11591173
""":return: the name of the branch, which is the shortest possible branch name"""
11601174
# use an instance method, for this we create a temporary Head instance
11611175
# which uses a repository that is available at least ( it makes no difference )
11621176
return git.Head(self.repo, self._branch_path).name
11631177

11641178
@property
1165-
def url(self):
1179+
def url(self) -> str:
11661180
""":return: The url to the repository which our module - repository refers to"""
11671181
return self._url
11681182

11691183
@property
1170-
def parent_commit(self):
1184+
def parent_commit(self) -> 'Commit_ish':
11711185
""":return: Commit instance with the tree containing the .gitmodules file
11721186
:note: will always point to the current head's commit if it was not set explicitly"""
11731187
if self._parent_commit is None:
11741188
return self.repo.commit()
11751189
return self._parent_commit
11761190

11771191
@property
1178-
def name(self):
1192+
def name(self) -> str:
11791193
""":return: The name of this submodule. It is used to identify it within the
11801194
.gitmodules file.
11811195
:note: by default, the name is the path at which to find the submodule, but

0 commit comments

Comments
 (0)