diff --git a/pinecone/utils/filter_builder.py b/pinecone/utils/filter_builder.py index 28e2d80b..2f7f8c74 100644 --- a/pinecone/utils/filter_builder.py +++ b/pinecone/utils/filter_builder.py @@ -117,12 +117,20 @@ def __ne__(self, value: object) -> Condition: # type: ignore[override] # -- set operators -------------------------------------------------------- + def _require_list(self, op: str, values: Any) -> None: + if not isinstance(values, (list, tuple)): + raise TypeError( + f"{op} requires a list of values, got {type(values).__name__}" + ) + def is_in(self, values: list[str | int | float | bool]) -> Condition: """``$in`` — value is in the given list.""" + self._require_list("is_in", values) return Condition({self._name: {"$in": values}}) def not_in(self, values: list[str | int | float | bool]) -> Condition: """``$nin`` — value is not in the given list.""" + self._require_list("not_in", values) return Condition({self._name: {"$nin": values}}) # -- exists operator ------------------------------------------------------ diff --git a/tests/unit/utils/test_filter_builder.py b/tests/unit/utils/test_filter_builder.py index 4b31ffff..cd25649b 100644 --- a/tests/unit/utils/test_filter_builder.py +++ b/tests/unit/utils/test_filter_builder.py @@ -64,6 +64,18 @@ def test_field_not_in(self) -> None: result = Field("tag").not_in(["spam"]).to_dict() assert result == {"tag": {"$nin": ["spam"]}} + def test_field_is_in_accepts_tuple(self) -> None: + result = Field("color").is_in(("red", "blue")).to_dict() + assert result == {"color": {"$in": ("red", "blue")}} + + def test_is_in_requires_list(self) -> None: + with pytest.raises(TypeError, match="list"): + Field("genre").is_in("drama") # type: ignore[arg-type] + + def test_not_in_requires_list(self) -> None: + with pytest.raises(TypeError, match="list"): + Field("genre").not_in("drama") # type: ignore[arg-type] + class TestFieldExists: def test_field_exists(self) -> None: