diff --git a/git/util.py b/git/util.py index 2d4cc7c23..bac1bc98b 100644 --- a/git/util.py +++ b/git/util.py @@ -1333,10 +1333,10 @@ def __getattr__(self, attr: str) -> T_IterableObj: def __getitem__( # type: ignore[override] # pyright: ignore[reportIncompatibleMethodOverride] self, index: Union[SupportsIndex, int, slice, str] ) -> T_IterableObj: - if isinstance(index, int): - return list.__getitem__(self, index) - elif isinstance(index, slice): + if isinstance(index, slice): raise ValueError("Index should be an int or str") + elif not isinstance(index, str): + return list.__getitem__(self, index) else: try: return self.__getattr__(cast(str, index)) diff --git a/test/test_util.py b/test/test_util.py index acbff17b7..f01d619c5 100644 --- a/test/test_util.py +++ b/test/test_util.py @@ -280,6 +280,45 @@ def __repr__(self): return f"{type(self).__name__}({self.name!r})" +@pytest.mark.parametrize("prefix", ["", "refs/"]) +@pytest.mark.parametrize("position", [0, -1]) +def test_iterable_list_accepts_index_protocol(prefix, position): + class Index: + def __index__(self): + return position + + values = IterableList("name", prefix) + members = [_Member(prefix + name) for name in ("one", "two")] + values.extend(members) + assert values[Index()] is members[position] + + +@pytest.mark.parametrize("position", [2, -3]) +def test_iterable_list_index_protocol_preserves_bounds_errors(position): + class Index: + def __index__(self): + return position + + values = IterableList("name") + values.extend([_Member("one"), _Member("two")]) + with pytest.raises(IndexError): + values[Index()] + + +def test_iterable_list_index_protocol_preserves_named_lookup_and_slice_rejection(): + values = IterableList("name", "refs/") + named = _Member("refs/0") + values.extend([named, _Member("refs/one")]) + assert values["0"] is named + assert values[False] is named + with pytest.raises(IndexError): + values["missing"] + with pytest.raises(ValueError): + values[:1] + with pytest.raises(TypeError): + values[0.0] + + @ddt.ddt class TestUtils(TestBase): """Tests for most utilities in :mod:`git.util`."""