diff --git a/integration/test_collection_filter.py b/integration/test_collection_filter.py index 089258da1..f3916d83a 100644 --- a/integration/test_collection_filter.py +++ b/integration/test_collection_filter.py @@ -278,13 +278,14 @@ def test_filters_comparison( ], ) def test_filters_contains( + recwarn: pytest.WarningsRecorder, collection_factory: CollectionFactory, weaviate_filter: _FilterValue, results: List[int], require_version: Optional[tuple[int, int, int]], ) -> None: collection = collection_factory( - vectorizer_config=Configure.Vectorizer.none(), + vector_config=Configure.Vectors.self_provided(), properties=[ Property(name="text", data_type=DataType.TEXT), Property(name="texts", data_type=DataType.TEXT_ARRAY), @@ -380,6 +381,12 @@ def test_filters_contains( uuids = [uuids[result] for result in results] assert all(obj.uuid in uuids for obj in objects) + # Check for warnings to make sure booleans are handled as their correct type and are not sent as ints + if len(recwarn) != 0: + for rwarning in recwarn.list: + print(rwarning.message) + assert len(recwarn) == 0 + @pytest.mark.parametrize( "weaviate_filter,results", diff --git a/weaviate/collections/filters.py b/weaviate/collections/filters.py index 40b50e1f7..41aebf95c 100644 --- a/weaviate/collections/filters.py +++ b/weaviate/collections/filters.py @@ -40,18 +40,30 @@ def convert(weav_filter: Optional[_Filters]) -> Optional[base_pb2.Filters]: @staticmethod def __value_filter(weav_filter: _FilterValue) -> base_pb2.Filters: + operator = weav_filter.operator._to_grpc() + target = _FilterToGRPC.__to_target(weav_filter.target) + if isinstance(weav_filter.value, bool): + # bool is a subclass of int in Python, so we need to handle it before the int check. Also for whatever reason + # the generated code from the proto files does not accept None for value_boolean, while it does for all other types. + return base_pb2.Filters( + operator=operator, + value_boolean=weav_filter.value, + target=target, + ) + return base_pb2.Filters( - operator=weav_filter.operator._to_grpc(), + operator=operator, value_text=_FilterToGRPC.__filter_to_text(weav_filter.value), - value_int=weav_filter.value if isinstance(weav_filter.value, int) else None, - value_boolean=weav_filter.value if isinstance(weav_filter.value, bool) else None, # type: ignore + value_int=weav_filter.value + if isinstance(weav_filter.value, int) and not isinstance(weav_filter.value, bool) + else None, value_number=(weav_filter.value if isinstance(weav_filter.value, float) else None), + value_boolean_array=_FilterToGRPC.__filter_to_bool_list(weav_filter.value), value_int_array=_FilterToGRPC.__filter_to_int_list(weav_filter.value), value_number_array=_FilterToGRPC.__filter_to_float_list(weav_filter.value), value_text_array=_FilterToGRPC.__filter_to_text_list(weav_filter.value), - value_boolean_array=_FilterToGRPC.__filter_to_bool_list(weav_filter.value), value_geo=_FilterToGRPC.__filter_to_geo(weav_filter.value), - target=_FilterToGRPC.__to_target(weav_filter.target), + target=target, ) @staticmethod @@ -137,7 +149,12 @@ def __filter_to_float_list(value: FilterValues) -> Optional[base_pb2.NumberArray @staticmethod def __filter_to_int_list(value: FilterValues) -> Optional[base_pb2.IntArray]: - if not isinstance(value, list) or not isinstance(value[0], int): + # bool is a subclass of int in Python, so the check must ensure it's not a bool + if ( + not isinstance(value, list) + or not isinstance(value[0], int) + or isinstance(value[0], bool) + ): return None return base_pb2.IntArray(values=cast(List[int], value))