diff --git a/pygit2/submodules.py b/pygit2/submodules.py index facf1c27..2af900f3 100644 --- a/pygit2/submodules.py +++ b/pygit2/submodules.py @@ -32,7 +32,7 @@ from ._pygit2 import Oid from .callbacks import RemoteCallbacks, git_fetch_options from .enums import SubmoduleIgnore, SubmoduleStatus -from .errors import check_error +from .errors import AlreadyExistsError, check_error from .ffi import C, ffi from .utils import decode_fs_path, decode_string, encode_string @@ -210,7 +210,11 @@ def get(self, name: str) -> Submodule | None: """ try: return self[name] - except KeyError: + except (KeyError, AlreadyExistsError): + # libgit2 reports GIT_EEXISTS, which check_error turns into + # AlreadyExistsError, when a repository exists at the path but was + # never registered as a submodule. There is still no submodule by + # that name, so report it the same way as a missing one. return None def add( diff --git a/test/test_submodule.py b/test/test_submodule.py index 5c26578a..6fa5cee1 100644 --- a/test/test_submodule.py +++ b/test/test_submodule.py @@ -68,6 +68,25 @@ def test_lookup_missing_submodule(repo: Repository) -> None: assert repo.submodules.get('does-not-exist') is None +def test_lookup_nested_repo_that_is_not_a_submodule(tmp_path: Path) -> None: + """A plain repository inside another is not a submodule. + + libgit2 reports GIT_EEXISTS for this case rather than GIT_ENOTFOUND, which + reaches Python as AlreadyExistsError. get() and __contains__ must still + describe it as absent, per their documented contracts. + """ + outer = pygit2.init_repository(tmp_path / 'outer') + pygit2.init_repository(tmp_path / 'outer' / 'nested') + + assert outer.submodules.get('nested') is None + assert 'nested' not in outer.submodules + + # __getitem__ keeps reporting the distinction, so callers that care can + # still tell "there is a repository there" from "there is nothing there". + with pytest.raises(pygit2.AlreadyExistsError): + outer.submodules['nested'] + + def test_listall_submodules(repo: Repository) -> None: submodules = repo.listall_submodules() assert len(submodules) == 1