internlm/SWE-Fixer-Train-110K huggingface dataset:
Repository: redis/redis-py

Issue:
ft.dropindex() crashes server
Hello, I'm using version `4.3.4` and found out that `dropindex()` crashes the server when the index is not present. [Related to](https://github.com/RediSearch/RediSearch/issues/2152)

What is more interesting is why is the library using an undocumented `FT.DROP`  command [see](https://github.com/redis/redis-py/blob/ae83d40384665e2533d2f181981f991a45f58555/redis/commands/search/commands.py#L22) rather than using `FT.DROPINDEX` which does not crash the server?


Discussion:
In the past FT.DROP was the drop command (here's a historic link): https://d128ysc22mu7qe.cloudfront.net/Commands/#ftdrop. Perhaps there's some cruft there.

@dvora-h want to change the behaviour to run FT.DROPINDEX? We might need to denote this in the release notes?
Grrr apparently I can't label today? @dvora-h can you mark "bug" and "breakingchange"

Resolving patch:
diff --git a/redis/commands/search/commands.py b/redis/commands/search/commands.py
--- a/redis/commands/search/commands.py
+++ b/redis/commands/search/commands.py
@@ -20,6 +20,7 @@
 ADD_CMD = "FT.ADD"
 ADDHASH_CMD = "FT.ADDHASH"
 DROP_CMD = "FT.DROP"
+DROPINDEX_CMD = "FT.DROPINDEX"
 EXPLAIN_CMD = "FT.EXPLAIN"
 EXPLAINCLI_CMD = "FT.EXPLAINCLI"
 DEL_CMD = "FT.DEL"
@@ -170,8 +171,8 @@ def dropindex(self, delete_documents=False):
 
         For more information see `FT.DROPINDEX <https://redis.io/commands/ft.dropindex>`_.
         """  # noqa
-        keep_str = "" if delete_documents else "KEEPDOCS"
-        return self.execute_command(DROP_CMD, self.index_name, keep_str)
+        delete_str = "DD" if delete_documents else ""
+        return self.execute_command(DROPINDEX_CMD, self.index_name, delete_str)
 
     def _add_document(
         self,


Test patch:
Repository: redis/redis-py

Issue:
Add support for missing command BITFIELD_RO



Discussion:

Resolving patch:
diff --git a/redis/commands/core.py b/redis/commands/core.py
--- a/redis/commands/core.py
+++ b/redis/commands/core.py
@@ -1504,6 +1504,29 @@ def bitfield(
         """
         return BitFieldOperation(self, key, default_overflow=default_overflow)
 
+    def bitfield_ro(
+        self: Union["Redis", "AsyncRedis"],
+        key: KeyT,
+        encoding: str,
+        offset: BitfieldOffsetT,
+        items: Optional[list] = None,
+    ) -> ResponseT:
+        """
+        Return an array of the specified bitfield values
+        where the first value is found using ``encoding`` and ``offset``
+        parameters and remaining values are result of corresponding
+        encoding/offset pairs in optional list ``items``
+        Read-only variant of the BITFIELD command.
+
+        For more information see https://redis.io/commands/bitfield_ro
+        """
+        params = [key, "GET", encoding, offset]
+
+        items = items or []
+        for encoding, offset in items:
+            params.extend(["GET", encoding, offset])
+        return self.execute_command("BITFIELD_RO", *params)
+
     def bitop(self, operation: str, dest: KeyT, *keys: KeyT) -> ResponseT:
         """
         Perform a bitwise operation using ``operation`` between ``keys`` and


Test patch:
diff --git a/tests/test_asyncio/test_commands.py b/tests/test_asyncio/test_commands.py
--- a/tests/test_asyncio/test_commands.py
+++ b/tests/test_asyncio/test_commands.py
@@ -2953,6 +2953,19 @@ async def test_bitfield_operations(self, r: redis.Redis):
         )
         assert resp == [0, None, 255]
 
+    @skip_if_server_version_lt("6.0.0")
+    async def test_bitfield_ro(self, r: redis.Redis):
+        bf = r.bitfield("a")
+        resp = await bf.set("u8", 8, 255).execute()
+        assert resp == [0]
+
+        resp = await r.bitfield_ro("a", "u8", 0)
+        assert resp == [0]
+
+        items = [("u4", 8), ("u4", 12), ("u4", 13)]
+        resp = await r.bitfield_ro("a", "u8", 0, items)
+        assert resp == [0, 15, 15, 14]
+
     @skip_if_server_version_lt("4.0.0")
     async def test_memory_stats(self, r: redis.Redis):
         # put a key into the current db to make sure that "db.<current-db>"
diff --git a/tests/test_commands.py b/tests/test_commands.py
--- a/tests/test_commands.py
+++ b/tests/test_commands.py
@@ -4438,6 +4438,19 @@ def test_bitfield_operations(self, r):
         )
         assert resp == [0, None, 255]
 
+    @skip_if_server_version_lt("6.0.0")
+    def test_bitfield_ro(self, r: redis.Redis):
+        bf = r.bitfield("a")
+        resp = bf.set("u8", 8, 255).execute()
+        assert resp == [0]
+
+        resp = r.bitfield_ro("a", "u8", 0)
+        assert resp == [0]
+
+        items = [("u4", 8), ("u4", 12), ("u4", 13)]
+        resp = r.bitfield_ro("a", "u8", 0, items)
+        assert resp == [0, 15, 15, 14]
+
     @skip_if_server_version_lt("4.0.0")
     def test_memory_help(self, r):
         with pytest.raises(NotImplementedError):
Repository: redis/redis-py

Issue:
Need to mark TOPK.COUNT as deprecated, for Bloom 2.4.0
https://github.com/RedisBloom/RedisBloom/pull/512


Discussion:

Resolving patch:
diff --git a/redis/commands/bf/commands.py b/redis/commands/bf/commands.py
--- a/redis/commands/bf/commands.py
+++ b/redis/commands/bf/commands.py
@@ -1,3 +1,5 @@
+from deprecated import deprecated
+
 from redis.client import NEVER_DECODE
 from redis.exceptions import ModuleError
 from redis.utils import HIREDIS_AVAILABLE
@@ -318,6 +320,7 @@ def query(self, key, *items):
         """  # noqa
         return self.execute_command(TOPK_QUERY, key, *items)
 
+    @deprecated(version="4.4.0", reason="deprecated since redisbloom 2.4.0")
     def count(self, key, *items):
         """
         Return count for one `item` or more from `key`.


Test patch:
diff --git a/tests/test_asyncio/test_bloom.py b/tests/test_asyncio/test_bloom.py
--- a/tests/test_asyncio/test_bloom.py
+++ b/tests/test_asyncio/test_bloom.py
@@ -263,9 +263,10 @@ async def test_topk(modclient: redis.Redis):
     assert [1, 1, 0, 0, 1, 0, 0] == await modclient.topk().query(
         "topk", "A", "B", "C", "D", "E", "F", "G"
     )
-    assert [4, 3, 2, 3, 3, 0, 1] == await modclient.topk().count(
-        "topk", "A", "B", "C", "D", "E", "F", "G"
-    )
+    with pytest.deprecated_call():
+        assert [4, 3, 2, 3, 3, 0, 1] == await modclient.topk().count(
+            "topk", "A", "B", "C", "D", "E", "F", "G"
+        )
 
     # test full list
     assert await modclient.topk().reserve("topklist", 3, 50, 3, 0.9)
@@ -307,9 +308,10 @@ async def test_topk_incrby(modclient: redis.Redis):
     )
     res = await modclient.topk().incrby("topk", ["42", "xyzzy"], [8, 4])
     assert [None, "bar"] == res
-    assert [3, 6, 10, 4, 0] == await modclient.topk().count(
-        "topk", "bar", "baz", "42", "xyzzy", 4
-    )
+    with pytest.deprecated_call():
+        assert [3, 6, 10, 4, 0] == await modclient.topk().count(
+            "topk", "bar", "baz", "42", "xyzzy", 4
+        )
 
 
 # region Test T-Digest
diff --git a/tests/test_bloom.py b/tests/test_bloom.py
--- a/tests/test_bloom.py
+++ b/tests/test_bloom.py
@@ -265,9 +265,10 @@ def test_topk(client):
     assert [1, 1, 0, 0, 1, 0, 0] == client.topk().query(
         "topk", "A", "B", "C", "D", "E", "F", "G"
     )
-    assert [4, 3, 2, 3, 3, 0, 1] == client.topk().count(
-        "topk", "A", "B", "C", "D", "E", "F", "G"
-    )
+    with pytest.deprecated_call():
+        assert [4, 3, 2, 3, 3, 0, 1] == client.topk().count(
+            "topk", "A", "B", "C", "D", "E", "F", "G"
+        )
 
     # test full list
     assert client.topk().reserve("topklist", 3, 50, 3, 0.9)
@@ -307,9 +308,10 @@ def test_topk_incrby(client):
         "topk", ["bar", "baz", "42"], [3, 6, 2]
     )
     assert [None, "bar"] == client.topk().incrby("topk", ["42", "xyzzy"], [8, 4])
-    assert [3, 6, 10, 4, 0] == client.topk().count(
-        "topk", "bar", "baz", "42", "xyzzy", 4
-    )
+    with pytest.deprecated_call():
+        assert [3, 6, 10, 4, 0] == client.topk().count(
+            "topk", "bar", "baz", "42", "xyzzy", 4
+        )
 
 
 # region Test T-Digest
Repository: redis/redis-py

Issue:
Invalid Default Argument For LMPOP
**Version**: Confirmed on redis-py 4.3.4, still in main. Redis 7.0.5

**Platform**: Python 3.10, Windows 10. Any OS and python version can reproduce.

**Description**:
The code for LMPOP gives the direction a default argument of `None` which is not a valid argument for that function and would raise an error:
```py
>>> redis.lmpop(1, "example")
Traceback (most recent call last):
  ...
  File "site-packages\redis\commands\core.py", line 2551, in lmpop
    return self.execute_command("LMPOP", *args)
  File "site-packages\redis\client.py", line 1238, in execute_command
    return conn.retry.call_with_retry(
  ...
  File "site-packages\redis\connection.py", line 108, in encode
    raise DataError(
redis.exceptions.DataError: Invalid input of type: 'NoneType'. Convert to a bytes, string, int or float first.
```

Running something like `redis.lmpop(1, "example", direction="LEFT")` would not raise an error. The other functions around here do not have a default argument for direction.

Relevant code:
https://github.com/redis/redis-py/blob/936d49f4c1dd6cf0c2e3ad80de29f25eef81d8a9/redis/commands/core.py#L2552-L2569



Discussion:

Resolving patch:
diff --git a/redis/commands/core.py b/redis/commands/core.py
--- a/redis/commands/core.py
+++ b/redis/commands/core.py
@@ -2553,7 +2553,7 @@ def lmpop(
         self,
         num_keys: int,
         *args: List[str],
-        direction: str = None,
+        direction: str,
         count: Optional[int] = 1,
     ) -> Union[Awaitable[list], list]:
         """


Test patch:
Repository: redis/redis-py

Issue:
Add support for missing command LATENCY DOCTOR



Discussion:

Resolving patch:
diff --git a/redis/commands/core.py b/redis/commands/core.py
--- a/redis/commands/core.py
+++ b/redis/commands/core.py
@@ -980,6 +980,34 @@ def lastsave(self, **kwargs) -> ResponseT:
         """
         return self.execute_command("LASTSAVE", **kwargs)
 
+    def latency_doctor(self):
+        """Raise a NotImplementedError, as the client will not support LATENCY DOCTOR.
+        This funcion is best used within the redis-cli.
+
+        For more information see https://redis.io/commands/latency-doctor
+        """
+        raise NotImplementedError(
+            """
+            LATENCY DOCTOR is intentionally not implemented in the client.
+
+            For more information see https://redis.io/commands/latency-doctor
+            """
+        )
+
+    def latency_graph(self):
+        """Raise a NotImplementedError, as the client will not support LATENCY GRAPH.
+        This funcion is best used within the redis-cli.
+
+        For more information see https://redis.io/commands/latency-graph.
+        """
+        raise NotImplementedError(
+            """
+            LATENCY GRAPH is intentionally not implemented in the client.
+
+            For more information see https://redis.io/commands/latency-graph
+            """
+        )
+
     def lolwut(self, *version_numbers: Union[str, float], **kwargs) -> ResponseT:
         """
         Get the Redis version and a piece of generative computer art


Test patch:
diff --git a/tests/test_commands.py b/tests/test_commands.py
--- a/tests/test_commands.py
+++ b/tests/test_commands.py
@@ -4527,6 +4527,16 @@ def test_latency_histogram_not_implemented(self, r: redis.Redis):
         with pytest.raises(NotImplementedError):
             r.latency_histogram()
 
+    @skip_if_server_version_lt("7.0.0")
+    def test_latency_graph_not_implemented(self, r: redis.Redis):
+        with pytest.raises(NotImplementedError):
+            r.latency_graph()
+
+    @skip_if_server_version_lt("7.0.0")
+    def test_latency_doctor_not_implemented(self, r: redis.Redis):
+        with pytest.raises(NotImplementedError):
+            r.latency_doctor()
+
     @pytest.mark.onlynoncluster
     @skip_if_server_version_lt("4.0.0")
     @skip_if_redis_enterprise()
Repository: redis/redis-py

Issue:
Add support for missing command LATENCY RESET



Discussion:

Resolving patch:
diff --git a/redis/cluster.py b/redis/cluster.py
--- a/redis/cluster.py
+++ b/redis/cluster.py
@@ -265,6 +265,9 @@ class AbstractRedisCluster:
                 "READWRITE",
                 "TIME",
                 "GRAPH.CONFIG",
+                "LATENCY HISTORY",
+                "LATENCY LATEST",
+                "LATENCY RESET",
             ],
             DEFAULT_NODE,
         ),
diff --git a/redis/commands/core.py b/redis/commands/core.py
--- a/redis/commands/core.py
+++ b/redis/commands/core.py
@@ -1151,6 +1151,30 @@ def latency_histogram(self, *args):
             "LATENCY HISTOGRAM is intentionally not implemented in the client."
         )
 
+    def latency_history(self, event: str) -> ResponseT:
+        """
+        Returns the raw data of the ``event``'s latency spikes time series.
+
+        For more information see https://redis.io/commands/latency-history
+        """
+        return self.execute_command("LATENCY HISTORY", event)
+
+    def latency_latest(self) -> ResponseT:
+        """
+        Reports the latest latency events logged.
+
+        For more information see https://redis.io/commands/latency-latest
+        """
+        return self.execute_command("LATENCY LATEST")
+
+    def latency_reset(self, *events: str) -> ResponseT:
+        """
+        Resets the latency spikes time series of all, or only some, events.
+
+        For more information see https://redis.io/commands/latency-reset
+        """
+        return self.execute_command("LATENCY RESET", *events)
+
     def ping(self, **kwargs) -> ResponseT:
         """
         Ping the Redis server


Test patch:
diff --git a/tests/test_commands.py b/tests/test_commands.py
--- a/tests/test_commands.py
+++ b/tests/test_commands.py
@@ -4527,16 +4527,23 @@ def test_latency_histogram_not_implemented(self, r: redis.Redis):
         with pytest.raises(NotImplementedError):
             r.latency_histogram()
 
-    @skip_if_server_version_lt("7.0.0")
     def test_latency_graph_not_implemented(self, r: redis.Redis):
         with pytest.raises(NotImplementedError):
             r.latency_graph()
 
-    @skip_if_server_version_lt("7.0.0")
     def test_latency_doctor_not_implemented(self, r: redis.Redis):
         with pytest.raises(NotImplementedError):
             r.latency_doctor()
 
+    def test_latency_history(self, r: redis.Redis):
+        assert r.latency_history("command") == []
+
+    def test_latency_latest(self, r: redis.Redis):
+        assert r.latency_latest() == []
+
+    def test_latency_reset(self, r: redis.Redis):
+        assert r.latency_reset() == 0
+
     @pytest.mark.onlynoncluster
     @skip_if_server_version_lt("4.0.0")
     @skip_if_redis_enterprise()
Repository: redis/redis-py

Issue:
Add support for missing command CLUSTER FLUSHSLOTS



Discussion:

Resolving patch:
diff --git a/redis/commands/cluster.py b/redis/commands/cluster.py
--- a/redis/commands/cluster.py
+++ b/redis/commands/cluster.py
@@ -644,6 +644,16 @@ def cluster_links(self, target_node: "TargetNodesT") -> ResponseT:
         """
         return self.execute_command("CLUSTER LINKS", target_nodes=target_node)
 
+    def cluster_flushslots(self, target_nodes: Optional["TargetNodesT"] = None) -> None:
+        raise NotImplementedError(
+            "CLUSTER FLUSHSLOTS is intentionally not implemented in the client."
+        )
+
+    def cluster_bumpepoch(self, target_nodes: Optional["TargetNodesT"] = None) -> None:
+        raise NotImplementedError(
+            "CLUSTER BUMPEPOCH is intentionally not implemented in the client."
+        )
+
     def readonly(self, target_nodes: Optional["TargetNodesT"] = None) -> ResponseT:
         """
         Enables read queries.


Test patch:
diff --git a/tests/test_cluster.py b/tests/test_cluster.py
--- a/tests/test_cluster.py
+++ b/tests/test_cluster.py
@@ -1289,6 +1289,14 @@ def test_cluster_links(self, r):
         for i in range(0, len(res) - 1, 2):
             assert res[i][3] == res[i + 1][3]
 
+    def test_cluster_flshslots_not_implemented(self, r):
+        with pytest.raises(NotImplementedError):
+            r.cluster_flushslots()
+
+    def test_cluster_bumpepoch_not_implemented(self, r):
+        with pytest.raises(NotImplementedError):
+            r.cluster_bumpepoch()
+
     @skip_if_redis_enterprise()
     def test_readonly(self):
         r = get_mocked_redis_client(host=default_host, port=default_port)
Repository: redis/redis-py

Issue:
`set` and `expire` api diffrent handle to 'expire time' param

expire: https://github.com/redis/redis-py/blob/42b937fa1f73f3e8251eba5ec8ead2fcbaec7c50/redis/commands/core.py#L1592
set: https://github.com/redis/redis-py/blob/42b937fa1f73f3e8251eba5ec8ead2fcbaec7c50/redis/commands/core.py#L2175

The `set` api `ex`  should be a interger, but `expire`'s `time` can use a string(integer in  string type) as input.

It make me confusing. Both can also accept string type is more convenient.






Discussion:

Resolving patch:
diff --git a/redis/commands/core.py b/redis/commands/core.py
--- a/redis/commands/core.py
+++ b/redis/commands/core.py
@@ -2255,6 +2255,8 @@ def set(
                 pieces.append(int(ex.total_seconds()))
             elif isinstance(ex, int):
                 pieces.append(ex)
+            elif isinstance(ex, str) and ex.isdigit():
+                pieces.append(int(ex))
             else:
                 raise DataError("ex must be datetime.timedelta or int")
         if px is not None:


Test patch:
diff --git a/tests/test_commands.py b/tests/test_commands.py
--- a/tests/test_commands.py
+++ b/tests/test_commands.py
@@ -1600,6 +1600,13 @@ def test_set_ex(self, r):
         with pytest.raises(exceptions.DataError):
             assert r.set("a", "1", ex=10.0)
 
+    @skip_if_server_version_lt("2.6.0")
+    def test_set_ex_str(self, r):
+        assert r.set("a", "1", ex="10")
+        assert 0 < r.ttl("a") <= 10
+        with pytest.raises(exceptions.DataError):
+            assert r.set("a", "1", ex="10.5")
+
     @skip_if_server_version_lt("2.6.0")
     def test_set_ex_timedelta(self, r):
         expire_at = datetime.timedelta(seconds=60)
Repository: redis/redis-py

Issue:
no type checking with __eq__ in all the graph classes
**Version**: redis-py version 4.4.0 (redis version shouldnt matter but i'm using redis-stack 6.2.4-v3)

**Platform**: python version 3.10.9 (but should effect all versions) on wsl Ubuntu 20.04.5 LTS

**Description**: none of the redis graph classes check the types when checking equality 
```python
import redis.commands.graph as redisGraph
foo = redisGraph.Node()

foo == None # this line causes the error
```
```python 
AttributeError: 'NoneType' object has no attribute 'label'
```
you get the same error when checking against any type that is not a `Node`

it also happens with the `Edge` class
```python
bar = redisGraph.Edge(foo,"",foo)
bar == ""
```
```python
AttributeError: 'str' object has no attribute 'src_node'
```
and also the `Path` class
```python
baz = redisGraph.Path([],[])
baz == 4
```
```python
AttributeError: 'int' object has no attribute 'nodes'
```
i suspect adding this sort of code in would fix it
```python
# Check that the rhs the correct type
if not isinstance(rhs, type(self)):
    return False
```


Discussion:

Resolving patch:
diff --git a/redis/commands/graph/edge.py b/redis/commands/graph/edge.py
--- a/redis/commands/graph/edge.py
+++ b/redis/commands/graph/edge.py
@@ -61,6 +61,10 @@ def __str__(self):
         return res
 
     def __eq__(self, rhs):
+        # Type checking
+        if not isinstance(rhs, Edge):
+            return False
+
         # Quick positive check, if both IDs are set.
         if self.id is not None and rhs.id is not None and self.id == rhs.id:
             return True
diff --git a/redis/commands/graph/node.py b/redis/commands/graph/node.py
--- a/redis/commands/graph/node.py
+++ b/redis/commands/graph/node.py
@@ -65,6 +65,10 @@ def __str__(self):
         return res
 
     def __eq__(self, rhs):
+        # Type checking
+        if not isinstance(rhs, Node):
+            return False
+
         # Quick positive check, if both IDs are set.
         if self.id is not None and rhs.id is not None and self.id != rhs.id:
             return False
diff --git a/redis/commands/graph/path.py b/redis/commands/graph/path.py
--- a/redis/commands/graph/path.py
+++ b/redis/commands/graph/path.py
@@ -54,6 +54,10 @@ def add_edge(self, edge):
         return self
 
     def __eq__(self, other):
+        # Type checking
+        if not isinstance(other, Path):
+            return False
+
         return self.nodes() == other.nodes() and self.edges() == other.edges()
 
     def __str__(self):


Test patch:
Repository: redis/redis-py

Issue:
Add support for BF.CARD



Discussion:
I'll take it

Resolving patch:
diff --git a/redis/commands/bf/__init__.py b/redis/commands/bf/__init__.py
--- a/redis/commands/bf/__init__.py
+++ b/redis/commands/bf/__init__.py
@@ -198,6 +198,7 @@ def __init__(self, client, **kwargs):
             # BF_MEXISTS: spaceHolder,
             # BF_SCANDUMP: spaceHolder,
             # BF_LOADCHUNK: spaceHolder,
+            # BF_CARD: spaceHolder,
             BF_INFO: BFInfo,
         }
 
diff --git a/redis/commands/bf/commands.py b/redis/commands/bf/commands.py
--- a/redis/commands/bf/commands.py
+++ b/redis/commands/bf/commands.py
@@ -11,6 +11,7 @@
 BF_SCANDUMP = "BF.SCANDUMP"
 BF_LOADCHUNK = "BF.LOADCHUNK"
 BF_INFO = "BF.INFO"
+BF_CARD = "BF.CARD"
 
 CF_RESERVE = "CF.RESERVE"
 CF_ADD = "CF.ADD"
@@ -165,6 +166,14 @@ def info(self, key):
         """  # noqa
         return self.execute_command(BF_INFO, key)
 
+    def card(self, key):
+        """
+        Returns the cardinality of a Bloom filter - number of items that were added to a Bloom filter and detected as unique
+        (items that caused at least one bit to be set in at least one sub-filter).
+        For more information see `BF.CARD <https://redis.io/commands/bf.card>`_.
+        """  # noqa
+        return self.execute_command(BF_CARD, key)
+
 
 class CFCommands:
     """Cuckoo Filter commands."""


Test patch:
diff --git a/tests/test_asyncio/test_bloom.py b/tests/test_asyncio/test_bloom.py
--- a/tests/test_asyncio/test_bloom.py
+++ b/tests/test_asyncio/test_bloom.py
@@ -149,6 +149,21 @@ async def test_bf_info(modclient: redis.Redis):
         assert True
 
 
+@pytest.mark.redismod
+async def test_bf_card(modclient: redis.Redis):
+    # return 0 if the key does not exist
+    assert await modclient.bf().card("not_exist") == 0
+
+    # Store a filter
+    assert await modclient.bf().add("bf1", "item_foo") == 1
+    assert await modclient.bf().card("bf1") == 1
+
+    # Error when key is of a type other than Bloom filter.
+    with pytest.raises(redis.ResponseError):
+        await modclient.set("setKey", "value")
+        await modclient.bf().card("setKey")
+
+
 # region Test Cuckoo Filter
 @pytest.mark.redismod
 async def test_cf_add_and_insert(modclient: redis.Redis):
diff --git a/tests/test_bloom.py b/tests/test_bloom.py
--- a/tests/test_bloom.py
+++ b/tests/test_bloom.py
@@ -165,6 +165,21 @@ def test_bf_info(client):
         assert True
 
 
+@pytest.mark.redismod
+def test_bf_card(client):
+    # return 0 if the key does not exist
+    assert client.bf().card("not_exist") == 0
+
+    # Store a filter
+    assert client.bf().add("bf1", "item_foo") == 1
+    assert client.bf().card("bf1") == 1
+
+    # Error when key is of a type other than Bloom filter.
+    with pytest.raises(redis.ResponseError):
+        client.set("setKey", "value")
+        client.bf().card("setKey")
+
+
 # region Test Cuckoo Filter
 @pytest.mark.redismod
 def test_cf_add_and_insert(client):