diff --git a/news/529.feature b/news/529.feature new file mode 100644 index 000000000..e5b05dbb4 --- /dev/null +++ b/news/529.feature @@ -0,0 +1 @@ +ListConfig.__contains__ optimized, about 15x faster in a benchmark diff --git a/omegaconf/listconfig.py b/omegaconf/listconfig.py index 1b6d2cc49..5c1aaee90 100644 --- a/omegaconf/listconfig.py +++ b/omegaconf/listconfig.py @@ -539,7 +539,18 @@ def __iadd__(self, other: Iterable[Any]) -> "ListConfig": return self def __contains__(self, item: Any) -> bool: - for x in iter(self): + if self._is_none(): + raise TypeError( + "Cannot check if an item is in a ListConfig object representing None" + ) + if self._is_missing(): + raise MissingMandatoryValue( + "Cannot check if an item is in missing ListConfig" + ) + + lst = self.__dict__["_content"] + for x in lst: + x = x._dereference_node() if x == item: return True return False diff --git a/tests/test_basic_ops_list.py b/tests/test_basic_ops_list.py index 2bed50cc1..ef7bddb84 100644 --- a/tests/test_basic_ops_list.py +++ b/tests/test_basic_ops_list.py @@ -119,6 +119,32 @@ def test_in_with_interpolation() -> None: assert 10 in c.a +@pytest.mark.parametrize( + ("lst", "expected"), + [ + pytest.param( + ListConfig(content=None), + pytest.raises( + TypeError, + match="Cannot check if an item is in a ListConfig object representing None", + ), + id="ListConfig(None)", + ), + pytest.param( + ListConfig(content="???"), + pytest.raises( + MissingMandatoryValue, + match="Cannot check if an item is in missing ListConfig", + ), + id="ListConfig(???)", + ), + ], +) +def test_not_in_special_lists(lst: Any, expected: Any) -> None: + with expected: + "foo" not in lst + + def test_list_config_with_list() -> None: c = OmegaConf.create([]) assert isinstance(c, ListConfig)