Repository: redis/redis-py

Issue:
Add support for JSON commands in Async Cluster
It seems that the .json() ability [is supported in the Cluster client](https://github.com/redis/redis-py/pull/2032
) but not in Async Cluster client.

```python
from redis.asyncio.cluster import RedisCluster
client = RedisCluster()
await client.json().get("test")
```

`AttributeError: 'RedisCluster' object has no attribute 'json'`




Discussion:
Supported in 4.4.0.
This doesn't seem to work still 
AttributeError: 'RedisCluster' object has no attribute 'json'
when using redis.asyncio.cluster.RedisCluster (version 4.5.1)
@dvora-h can you double check this?
This still doesn't work with redis.asyncio. I'm using the latest version(4.5.5)
@chayim I can confirm @bharatbots's findings, FWIW
@chayim @bharatbots 

Did some more digging / testing. Long story short, the comments in [PR #2423](https://github.com/redis/redis-py/pull/2423) are correct - `redis.commands.redismodules.AsyncRedisModuleCommands` needs to be added to the inherited classes for `redis.asyncio.cluster.RedisCluster` and `redis.asyncio.cluster.ClusterPipeline`.

**ALSO**, an implementation of `set_response_callback` needs to be added to the cluster pipeline class that propagates the supplied callback to the bound client's associated `Node`'s.

From my testing, this seems to work just fine:

```python
def set_response_callback(self, command: str, callback: Callable[..., Any]) -> None:
    """Set a custom response callback."""
    self._client.set_response_callback(command, callback)

    for node in self._client.nodes_manager.nodes_cache.values():
        node.response_callbacks[command] = callback
```

Resolving patch:
diff --git a/redis/commands/cluster.py b/redis/commands/cluster.py
--- a/redis/commands/cluster.py
+++ b/redis/commands/cluster.py
@@ -44,7 +44,7 @@
     ScriptCommands,
 )
 from .helpers import list_or_args
-from .redismodules import RedisModuleCommands
+from .redismodules import AsyncRedisModuleCommands, RedisModuleCommands
 
 if TYPE_CHECKING:
     from redis.asyncio.cluster import TargetNodesT
@@ -907,6 +907,7 @@ class AsyncRedisClusterCommands(
     AsyncFunctionCommands,
     AsyncGearsCommands,
     AsyncModuleCommands,
+    AsyncRedisModuleCommands,
 ):
     """
     A class for all Redis Cluster 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
@@ -15,7 +15,6 @@ def intlist(obj):
     return [int(v) for v in obj]
 
 
-@pytest.mark.redismod
 async def test_create(decoded_r: redis.Redis):
     """Test CREATE/RESERVE calls"""
     assert await decoded_r.bf().create("bloom", 0.01, 1000)
@@ -30,13 +29,11 @@ async def test_create(decoded_r: redis.Redis):
     assert await decoded_r.topk().reserve("topk", 5, 100, 5, 0.9)
 
 
-@pytest.mark.redismod
 @pytest.mark.experimental
 async def test_tdigest_create(decoded_r: redis.Redis):
     assert await decoded_r.tdigest().create("tDigest", 100)
 
 
-@pytest.mark.redismod
 async def test_bf_add(decoded_r: redis.Redis):
     assert await decoded_r.bf().create("bloom", 0.01, 1000)
     assert 1 == await decoded_r.bf().add("bloom", "foo")
@@ -49,7 +46,6 @@ async def test_bf_add(decoded_r: redis.Redis):
     assert [1, 0] == intlist(await decoded_r.bf().mexists("bloom", "foo", "noexist"))
 
 
-@pytest.mark.redismod
 async def test_bf_insert(decoded_r: redis.Redis):
     assert await decoded_r.bf().create("bloom", 0.01, 1000)
     assert [1] == intlist(await decoded_r.bf().insert("bloom", ["foo"]))
@@ -80,7 +76,6 @@ async def test_bf_insert(decoded_r: redis.Redis):
     )
 
 
-@pytest.mark.redismod
 async def test_bf_scandump_and_loadchunk(decoded_r: redis.Redis):
     # Store a filter
     await decoded_r.bf().create("myBloom", "0.0001", "1000")
@@ -132,7 +127,6 @@ async def do_verify():
     await decoded_r.bf().create("myBloom", "0.0001", "10000000")
 
 
-@pytest.mark.redismod
 async def test_bf_info(decoded_r: redis.Redis):
     expansion = 4
     # Store a filter
@@ -164,7 +158,6 @@ async def test_bf_info(decoded_r: redis.Redis):
         assert True
 
 
-@pytest.mark.redismod
 async def test_bf_card(decoded_r: redis.Redis):
     # return 0 if the key does not exist
     assert await decoded_r.bf().card("not_exist") == 0
@@ -179,7 +172,6 @@ async def test_bf_card(decoded_r: redis.Redis):
         await decoded_r.bf().card("setKey")
 
 
-@pytest.mark.redismod
 async def test_cf_add_and_insert(decoded_r: redis.Redis):
     assert await decoded_r.cf().create("cuckoo", 1000)
     assert await decoded_r.cf().add("cuckoo", "filter")
@@ -205,7 +197,6 @@ async def test_cf_add_and_insert(decoded_r: redis.Redis):
     )
 
 
-@pytest.mark.redismod
 async def test_cf_exists_and_del(decoded_r: redis.Redis):
     assert await decoded_r.cf().create("cuckoo", 1000)
     assert await decoded_r.cf().add("cuckoo", "filter")
@@ -217,7 +208,6 @@ async def test_cf_exists_and_del(decoded_r: redis.Redis):
     assert 0 == await decoded_r.cf().count("cuckoo", "filter")
 
 
-@pytest.mark.redismod
 async def test_cms(decoded_r: redis.Redis):
     assert await decoded_r.cms().initbydim("dim", 1000, 5)
     assert await decoded_r.cms().initbyprob("prob", 0.01, 0.01)
@@ -233,7 +223,6 @@ async def test_cms(decoded_r: redis.Redis):
     assert 25 == info["count"]
 
 
-@pytest.mark.redismod
 @pytest.mark.onlynoncluster
 async def test_cms_merge(decoded_r: redis.Redis):
     assert await decoded_r.cms().initbydim("A", 1000, 5)
@@ -251,7 +240,6 @@ async def test_cms_merge(decoded_r: redis.Redis):
     assert [16, 15, 21] == await decoded_r.cms().query("C", "foo", "bar", "baz")
 
 
-@pytest.mark.redismod
 async def test_topk(decoded_r: redis.Redis):
     # test list with empty buckets
     assert await decoded_r.topk().reserve("topk", 3, 50, 4, 0.9)
@@ -332,7 +320,6 @@ async def test_topk(decoded_r: redis.Redis):
     assert 0.9 == round(float(info["decay"]), 1)
 
 
-@pytest.mark.redismod
 async def test_topk_incrby(decoded_r: redis.Redis):
     await decoded_r.flushdb()
     assert await decoded_r.topk().reserve("topk", 3, 10, 3, 1)
@@ -347,7 +334,6 @@ async def test_topk_incrby(decoded_r: redis.Redis):
         )
 
 
-@pytest.mark.redismod
 @pytest.mark.experimental
 async def test_tdigest_reset(decoded_r: redis.Redis):
     assert await decoded_r.tdigest().create("tDigest", 10)
@@ -364,7 +350,6 @@ async def test_tdigest_reset(decoded_r: redis.Redis):
     )
 
 
-@pytest.mark.redismod
 @pytest.mark.onlynoncluster
 async def test_tdigest_merge(decoded_r: redis.Redis):
     assert await decoded_r.tdigest().create("to-tDigest", 10)
@@ -392,7 +377,6 @@ async def test_tdigest_merge(decoded_r: redis.Redis):
     assert 4.0 == await decoded_r.tdigest().max("to-tDigest")
 
 
-@pytest.mark.redismod
 @pytest.mark.experimental
 async def test_tdigest_min_and_max(decoded_r: redis.Redis):
     assert await decoded_r.tdigest().create("tDigest", 100)
@@ -403,7 +387,6 @@ async def test_tdigest_min_and_max(decoded_r: redis.Redis):
     assert 1 == await decoded_r.tdigest().min("tDigest")
 
 
-@pytest.mark.redismod
 @pytest.mark.experimental
 @skip_ifmodversion_lt("2.4.0", "bf")
 async def test_tdigest_quantile(decoded_r: redis.Redis):
@@ -432,7 +415,6 @@ async def test_tdigest_quantile(decoded_r: redis.Redis):
     assert [3.0, 5.0] == res
 
 
-@pytest.mark.redismod
 @pytest.mark.experimental
 async def test_tdigest_cdf(decoded_r: redis.Redis):
     assert await decoded_r.tdigest().create("tDigest", 100)
@@ -444,7 +426,6 @@ async def test_tdigest_cdf(decoded_r: redis.Redis):
     assert [0.1, 0.9] == [round(x, 1) for x in res]
 
 
-@pytest.mark.redismod
 @pytest.mark.experimental
 @skip_ifmodversion_lt("2.4.0", "bf")
 async def test_tdigest_trimmed_mean(decoded_r: redis.Redis):
@@ -455,7 +436,6 @@ async def test_tdigest_trimmed_mean(decoded_r: redis.Redis):
     assert 4.5 == await decoded_r.tdigest().trimmed_mean("tDigest", 0.4, 0.5)
 
 
-@pytest.mark.redismod
 @pytest.mark.experimental
 async def test_tdigest_rank(decoded_r: redis.Redis):
     assert await decoded_r.tdigest().create("t-digest", 500)
@@ -466,7 +446,6 @@ async def test_tdigest_rank(decoded_r: redis.Redis):
     assert [-1, 20, 9] == await decoded_r.tdigest().rank("t-digest", -20, 20, 9)
 
 
-@pytest.mark.redismod
 @pytest.mark.experimental
 async def test_tdigest_revrank(decoded_r: redis.Redis):
     assert await decoded_r.tdigest().create("t-digest", 500)
@@ -476,7 +455,6 @@ async def test_tdigest_revrank(decoded_r: redis.Redis):
     assert [-1, 19, 9] == await decoded_r.tdigest().revrank("t-digest", 21, 0, 10)
 
 
-@pytest.mark.redismod
 @pytest.mark.experimental
 async def test_tdigest_byrank(decoded_r: redis.Redis):
     assert await decoded_r.tdigest().create("t-digest", 500)
@@ -488,7 +466,6 @@ async def test_tdigest_byrank(decoded_r: redis.Redis):
         (await decoded_r.tdigest().byrank("t-digest", -1))[0]
 
 
-@pytest.mark.redismod
 @pytest.mark.experimental
 async def test_tdigest_byrevrank(decoded_r: redis.Redis):
     assert await decoded_r.tdigest().create("t-digest", 500)
@@ -500,8 +477,7 @@ async def test_tdigest_byrevrank(decoded_r: redis.Redis):
         (await decoded_r.tdigest().byrevrank("t-digest", -1))[0]
 
 
-# @pytest.mark.redismod
-# async def test_pipeline(decoded_r: redis.Redis):
+# # async def test_pipeline(decoded_r: redis.Redis):
 #     pipeline = await decoded_r.bf().pipeline()
 #     assert not await decoded_r.bf().execute_command("get pipeline")
 #
diff --git a/tests/test_asyncio/test_graph.py b/tests/test_asyncio/test_graph.py
--- a/tests/test_asyncio/test_graph.py
+++ b/tests/test_asyncio/test_graph.py
@@ -6,14 +6,12 @@
 from tests.conftest import skip_if_redis_enterprise
 
 
-@pytest.mark.redismod
 async def test_bulk(decoded_r):
     with pytest.raises(NotImplementedError):
         await decoded_r.graph().bulk()
         await decoded_r.graph().bulk(foo="bar!")
 
 
-@pytest.mark.redismod
 async def test_graph_creation(decoded_r: redis.Redis):
     graph = decoded_r.graph()
 
@@ -58,7 +56,6 @@ async def test_graph_creation(decoded_r: redis.Redis):
     await graph.delete()
 
 
-@pytest.mark.redismod
 async def test_array_functions(decoded_r: redis.Redis):
     graph = decoded_r.graph()
 
@@ -81,7 +78,6 @@ async def test_array_functions(decoded_r: redis.Redis):
     assert [a] == result.result_set[0][0]
 
 
-@pytest.mark.redismod
 async def test_path(decoded_r: redis.Redis):
     node0 = Node(node_id=0, label="L1")
     node1 = Node(node_id=1, label="L1")
@@ -101,7 +97,6 @@ async def test_path(decoded_r: redis.Redis):
     assert expected_results == result.result_set
 
 
-@pytest.mark.redismod
 async def test_param(decoded_r: redis.Redis):
     params = [1, 2.3, "str", True, False, None, [0, 1, 2]]
     query = "RETURN $param"
@@ -111,7 +106,6 @@ async def test_param(decoded_r: redis.Redis):
         assert expected_results == result.result_set
 
 
-@pytest.mark.redismod
 async def test_map(decoded_r: redis.Redis):
     query = "RETURN {a:1, b:'str', c:NULL, d:[1,2,3], e:True, f:{x:1, y:2}}"
 
@@ -128,7 +122,6 @@ async def test_map(decoded_r: redis.Redis):
     assert actual == expected
 
 
-@pytest.mark.redismod
 async def test_point(decoded_r: redis.Redis):
     query = "RETURN point({latitude: 32.070794860, longitude: 34.820751118})"
     expected_lat = 32.070794860
@@ -145,7 +138,6 @@ async def test_point(decoded_r: redis.Redis):
     assert abs(actual["longitude"] - expected_lon) < 0.001
 
 
-@pytest.mark.redismod
 async def test_index_response(decoded_r: redis.Redis):
     result_set = await decoded_r.graph().query("CREATE INDEX ON :person(age)")
     assert 1 == result_set.indices_created
@@ -160,7 +152,6 @@ async def test_index_response(decoded_r: redis.Redis):
         await decoded_r.graph().query("DROP INDEX ON :person(age)")
 
 
-@pytest.mark.redismod
 async def test_stringify_query_result(decoded_r: redis.Redis):
     graph = decoded_r.graph()
 
@@ -214,7 +205,6 @@ async def test_stringify_query_result(decoded_r: redis.Redis):
     await graph.delete()
 
 
-@pytest.mark.redismod
 async def test_optional_match(decoded_r: redis.Redis):
     # Build a graph of form (a)-[R]->(b)
     node0 = Node(node_id=0, label="L1", properties={"value": "a"})
@@ -239,7 +229,6 @@ async def test_optional_match(decoded_r: redis.Redis):
     await graph.delete()
 
 
-@pytest.mark.redismod
 async def test_cached_execution(decoded_r: redis.Redis):
     await decoded_r.graph().query("CREATE ()")
 
@@ -259,7 +248,6 @@ async def test_cached_execution(decoded_r: redis.Redis):
     assert cached_result.cached_execution
 
 
-@pytest.mark.redismod
 async def test_slowlog(decoded_r: redis.Redis):
     create_query = """CREATE
     (:Rider {name:'Valentino Rossi'})-[:rides]->(:Team {name:'Yamaha'}),
@@ -272,7 +260,6 @@ async def test_slowlog(decoded_r: redis.Redis):
     assert results[0][2] == create_query
 
 
-@pytest.mark.redismod
 @pytest.mark.xfail(strict=False)
 async def test_query_timeout(decoded_r: redis.Redis):
     # Build a sample graph with 1000 nodes.
@@ -287,7 +274,6 @@ async def test_query_timeout(decoded_r: redis.Redis):
         assert False is False
 
 
-@pytest.mark.redismod
 async def test_read_only_query(decoded_r: redis.Redis):
     with pytest.raises(Exception):
         # Issue a write query, specifying read-only true,
@@ -296,7 +282,6 @@ async def test_read_only_query(decoded_r: redis.Redis):
         assert False is False
 
 
-@pytest.mark.redismod
 async def test_profile(decoded_r: redis.Redis):
     q = """UNWIND range(1, 3) AS x CREATE (p:Person {v:x})"""
     profile = (await decoded_r.graph().profile(q)).result_set
@@ -311,7 +296,6 @@ async def test_profile(decoded_r: redis.Redis):
     assert "Node By Label Scan | (p:Person) | Records produced: 3" in profile
 
 
-@pytest.mark.redismod
 @skip_if_redis_enterprise()
 async def test_config(decoded_r: redis.Redis):
     config_name = "RESULTSET_SIZE"
@@ -343,7 +327,6 @@ async def test_config(decoded_r: redis.Redis):
     await decoded_r.graph().config("RESULTSET_SIZE", -100, set=True)
 
 
-@pytest.mark.redismod
 @pytest.mark.onlynoncluster
 async def test_list_keys(decoded_r: redis.Redis):
     result = await decoded_r.graph().list_keys()
@@ -367,7 +350,6 @@ async def test_list_keys(decoded_r: redis.Redis):
     assert result == []
 
 
-@pytest.mark.redismod
 async def test_multi_label(decoded_r: redis.Redis):
     redis_graph = decoded_r.graph("g")
 
@@ -393,7 +375,6 @@ async def test_multi_label(decoded_r: redis.Redis):
         assert True
 
 
-@pytest.mark.redismod
 async def test_execution_plan(decoded_r: redis.Redis):
     redis_graph = decoded_r.graph("execution_plan")
     create_query = """CREATE
@@ -412,7 +393,6 @@ async def test_execution_plan(decoded_r: redis.Redis):
     await redis_graph.delete()
 
 
-@pytest.mark.redismod
 async def test_explain(decoded_r: redis.Redis):
     redis_graph = decoded_r.graph("execution_plan")
     # graph creation / population
diff --git a/tests/test_asyncio/test_json.py b/tests/test_asyncio/test_json.py
--- a/tests/test_asyncio/test_json.py
+++ b/tests/test_asyncio/test_json.py
@@ -5,7 +5,6 @@
 from tests.conftest import assert_resp_response, skip_ifmodversion_lt
 
 
-@pytest.mark.redismod
 async def test_json_setbinarykey(decoded_r: redis.Redis):
     d = {"hello": "world", b"some": "value"}
     with pytest.raises(TypeError):
@@ -13,7 +12,6 @@ async def test_json_setbinarykey(decoded_r: redis.Redis):
     assert await decoded_r.json().set("somekey", Path.root_path(), d, decode_keys=True)
 
 
-@pytest.mark.redismod
 async def test_json_setgetdeleteforget(decoded_r: redis.Redis):
     assert await decoded_r.json().set("foo", Path.root_path(), "bar")
     assert_resp_response(decoded_r, await decoded_r.json().get("foo"), "bar", [["bar"]])
@@ -23,13 +21,11 @@ async def test_json_setgetdeleteforget(decoded_r: redis.Redis):
     assert await decoded_r.exists("foo") == 0
 
 
-@pytest.mark.redismod
 async def test_jsonget(decoded_r: redis.Redis):
     await decoded_r.json().set("foo", Path.root_path(), "bar")
     assert_resp_response(decoded_r, await decoded_r.json().get("foo"), "bar", [["bar"]])
 
 
-@pytest.mark.redismod
 async def test_json_get_jset(decoded_r: redis.Redis):
     assert await decoded_r.json().set("foo", Path.root_path(), "bar")
     assert_resp_response(decoded_r, await decoded_r.json().get("foo"), "bar", [["bar"]])
@@ -38,7 +34,6 @@ async def test_json_get_jset(decoded_r: redis.Redis):
     assert await decoded_r.exists("foo") == 0
 
 
-@pytest.mark.redismod
 async def test_nonascii_setgetdelete(decoded_r: redis.Redis):
     assert await decoded_r.json().set("notascii", Path.root_path(), "hyvää-élève")
     res = "hyvää-élève"
@@ -49,7 +44,6 @@ async def test_nonascii_setgetdelete(decoded_r: redis.Redis):
     assert await decoded_r.exists("notascii") == 0
 
 
-@pytest.mark.redismod
 @skip_ifmodversion_lt("2.6.0", "ReJSON")
 async def test_json_merge(decoded_r: redis.Redis):
     # Test with root path $
@@ -84,7 +78,6 @@ async def test_json_merge(decoded_r: redis.Redis):
     }
 
 
-@pytest.mark.redismod
 async def test_jsonsetexistentialmodifiersshouldsucceed(decoded_r: redis.Redis):
     obj = {"foo": "bar"}
     assert await decoded_r.json().set("obj", Path.root_path(), obj)
@@ -102,7 +95,6 @@ async def test_jsonsetexistentialmodifiersshouldsucceed(decoded_r: redis.Redis):
         await decoded_r.json().set("obj", Path("foo"), "baz", nx=True, xx=True)
 
 
-@pytest.mark.redismod
 async def test_mgetshouldsucceed(decoded_r: redis.Redis):
     await decoded_r.json().set("1", Path.root_path(), 1)
     await decoded_r.json().set("2", Path.root_path(), 2)
@@ -111,7 +103,6 @@ async def test_mgetshouldsucceed(decoded_r: redis.Redis):
     assert await decoded_r.json().mget([1, 2], Path.root_path()) == [1, 2]
 
 
-@pytest.mark.redismod
 @pytest.mark.onlynoncluster
 @skip_ifmodversion_lt("2.6.0", "ReJSON")
 async def test_mset(decoded_r: redis.Redis):
@@ -123,7 +114,6 @@ async def test_mset(decoded_r: redis.Redis):
     assert await decoded_r.json().mget(["1", "2"], Path.root_path()) == [1, 2]
 
 
-@pytest.mark.redismod
 @skip_ifmodversion_lt("99.99.99", "ReJSON")  # todo: update after the release
 async def test_clear(decoded_r: redis.Redis):
     await decoded_r.json().set("arr", Path.root_path(), [0, 1, 2, 3, 4])
@@ -131,7 +121,6 @@ async def test_clear(decoded_r: redis.Redis):
     assert_resp_response(decoded_r, await decoded_r.json().get("arr"), [], [[[]]])
 
 
-@pytest.mark.redismod
 async def test_type(decoded_r: redis.Redis):
     await decoded_r.json().set("1", Path.root_path(), 1)
     assert_resp_response(
@@ -145,7 +134,6 @@ async def test_type(decoded_r: redis.Redis):
     )
 
 
-@pytest.mark.redismod
 async def test_numincrby(decoded_r):
     await decoded_r.json().set("num", Path.root_path(), 1)
     assert_resp_response(
@@ -157,7 +145,6 @@ async def test_numincrby(decoded_r):
     assert_resp_response(decoded_r, res, 1.25, [1.25])
 
 
-@pytest.mark.redismod
 async def test_nummultby(decoded_r: redis.Redis):
     await decoded_r.json().set("num", Path.root_path(), 1)
 
@@ -170,7 +157,6 @@ async def test_nummultby(decoded_r: redis.Redis):
         assert_resp_response(decoded_r, res, 2.5, [2.5])
 
 
-@pytest.mark.redismod
 @skip_ifmodversion_lt("99.99.99", "ReJSON")  # todo: update after the release
 async def test_toggle(decoded_r: redis.Redis):
     await decoded_r.json().set("bool", Path.root_path(), False)
@@ -182,7 +168,6 @@ async def test_toggle(decoded_r: redis.Redis):
         await decoded_r.json().toggle("num", Path.root_path())
 
 
-@pytest.mark.redismod
 async def test_strappend(decoded_r: redis.Redis):
     await decoded_r.json().set("jsonkey", Path.root_path(), "foo")
     assert 6 == await decoded_r.json().strappend("jsonkey", "bar")
@@ -190,7 +175,6 @@ async def test_strappend(decoded_r: redis.Redis):
     assert_resp_response(decoded_r, res, "foobar", [["foobar"]])
 
 
-@pytest.mark.redismod
 async def test_strlen(decoded_r: redis.Redis):
     await decoded_r.json().set("str", Path.root_path(), "foo")
     assert 3 == await decoded_r.json().strlen("str", Path.root_path())
@@ -199,7 +183,6 @@ async def test_strlen(decoded_r: redis.Redis):
     assert 6 == await decoded_r.json().strlen("str")
 
 
-@pytest.mark.redismod
 async def test_arrappend(decoded_r: redis.Redis):
     await decoded_r.json().set("arr", Path.root_path(), [1])
     assert 2 == await decoded_r.json().arrappend("arr", Path.root_path(), 2)
@@ -207,7 +190,6 @@ async def test_arrappend(decoded_r: redis.Redis):
     assert 7 == await decoded_r.json().arrappend("arr", Path.root_path(), *[5, 6, 7])
 
 
-@pytest.mark.redismod
 async def test_arrindex(decoded_r: redis.Redis):
     r_path = Path.root_path()
     await decoded_r.json().set("arr", r_path, [0, 1, 2, 3, 4])
@@ -220,7 +202,6 @@ async def test_arrindex(decoded_r: redis.Redis):
     assert -1 == await decoded_r.json().arrindex("arr", r_path, 4, start=1, stop=3)
 
 
-@pytest.mark.redismod
 async def test_arrinsert(decoded_r: redis.Redis):
     await decoded_r.json().set("arr", Path.root_path(), [0, 4])
     assert 5 == await decoded_r.json().arrinsert("arr", Path.root_path(), 1, *[1, 2, 3])
@@ -234,7 +215,6 @@ async def test_arrinsert(decoded_r: redis.Redis):
     assert_resp_response(decoded_r, await decoded_r.json().get("val2"), res, [[res]])
 
 
-@pytest.mark.redismod
 async def test_arrlen(decoded_r: redis.Redis):
     await decoded_r.json().set("arr", Path.root_path(), [0, 1, 2, 3, 4])
     assert 5 == await decoded_r.json().arrlen("arr", Path.root_path())
@@ -242,7 +222,6 @@ async def test_arrlen(decoded_r: redis.Redis):
     assert await decoded_r.json().arrlen("fakekey") is None
 
 
-@pytest.mark.redismod
 async def test_arrpop(decoded_r: redis.Redis):
     await decoded_r.json().set("arr", Path.root_path(), [0, 1, 2, 3, 4])
     assert 4 == await decoded_r.json().arrpop("arr", Path.root_path(), 4)
@@ -260,7 +239,6 @@ async def test_arrpop(decoded_r: redis.Redis):
     assert await decoded_r.json().arrpop("arr") is None
 
 
-@pytest.mark.redismod
 async def test_arrtrim(decoded_r: redis.Redis):
     await decoded_r.json().set("arr", Path.root_path(), [0, 1, 2, 3, 4])
     assert 3 == await decoded_r.json().arrtrim("arr", Path.root_path(), 1, 3)
@@ -284,7 +262,6 @@ async def test_arrtrim(decoded_r: redis.Redis):
     assert 0 == await decoded_r.json().arrtrim("arr", Path.root_path(), 9, 11)
 
 
-@pytest.mark.redismod
 async def test_resp(decoded_r: redis.Redis):
     obj = {"foo": "bar", "baz": 1, "qaz": True}
     await decoded_r.json().set("obj", Path.root_path(), obj)
@@ -294,7 +271,6 @@ async def test_resp(decoded_r: redis.Redis):
     assert isinstance(await decoded_r.json().resp("obj"), list)
 
 
-@pytest.mark.redismod
 async def test_objkeys(decoded_r: redis.Redis):
     obj = {"foo": "bar", "baz": "qaz"}
     await decoded_r.json().set("obj", Path.root_path(), obj)
@@ -311,7 +287,6 @@ async def test_objkeys(decoded_r: redis.Redis):
     assert await decoded_r.json().objkeys("fakekey") is None
 
 
-@pytest.mark.redismod
 async def test_objlen(decoded_r: redis.Redis):
     obj = {"foo": "bar", "baz": "qaz"}
     await decoded_r.json().set("obj", Path.root_path(), obj)
@@ -345,7 +320,6 @@ async def test_objlen(decoded_r: redis.Redis):
 #     assert await decoded_r.get("foo") is None
 
 
-@pytest.mark.redismod
 async def test_json_delete_with_dollar(decoded_r: redis.Redis):
     doc1 = {"a": 1, "nested": {"a": 2, "b": 3}}
     assert await decoded_r.json().set("doc1", "$", doc1)
@@ -399,7 +373,6 @@ async def test_json_delete_with_dollar(decoded_r: redis.Redis):
     await decoded_r.json().delete("not_a_document", "..a")
 
 
-@pytest.mark.redismod
 async def test_json_forget_with_dollar(decoded_r: redis.Redis):
     doc1 = {"a": 1, "nested": {"a": 2, "b": 3}}
     assert await decoded_r.json().set("doc1", "$", doc1)
@@ -452,7 +425,7 @@ async def test_json_forget_with_dollar(decoded_r: redis.Redis):
     await decoded_r.json().forget("not_a_document", "..a")
 
 
-@pytest.mark.redismod
+@pytest.mark.onlynoncluster
 async def test_json_mget_dollar(decoded_r: redis.Redis):
     # Test mget with multi paths
     await decoded_r.json().set(
@@ -488,7 +461,6 @@ async def test_json_mget_dollar(decoded_r: redis.Redis):
     assert res == [None, None]
 
 
-@pytest.mark.redismod
 async def test_numby_commands_dollar(decoded_r: redis.Redis):
     # Test NUMINCRBY
     await decoded_r.json().set(
@@ -543,7 +515,6 @@ async def test_numby_commands_dollar(decoded_r: redis.Redis):
         await decoded_r.json().nummultby("doc1", ".b[0].a", 3) == 6
 
 
-@pytest.mark.redismod
 async def test_strappend_dollar(decoded_r: redis.Redis):
     await decoded_r.json().set(
         "doc1", "$", {"a": "foo", "nested1": {"a": "hello"}, "nested2": {"a": 31}}
@@ -574,7 +545,6 @@ async def test_strappend_dollar(decoded_r: redis.Redis):
         await decoded_r.json().strappend("doc1", "piu")
 
 
-@pytest.mark.redismod
 async def test_strlen_dollar(decoded_r: redis.Redis):
     # Test multi
     await decoded_r.json().set(
@@ -595,7 +565,6 @@ async def test_strlen_dollar(decoded_r: redis.Redis):
         await decoded_r.json().strlen("non_existing_doc", "$..a")
 
 
-@pytest.mark.redismod
 async def test_arrappend_dollar(decoded_r: redis.Redis):
     await decoded_r.json().set(
         "doc1",
@@ -669,7 +638,6 @@ async def test_arrappend_dollar(decoded_r: redis.Redis):
         await decoded_r.json().arrappend("non_existing_doc", "$..a")
 
 
-@pytest.mark.redismod
 async def test_arrinsert_dollar(decoded_r: redis.Redis):
     await decoded_r.json().set(
         "doc1",
@@ -708,7 +676,6 @@ async def test_arrinsert_dollar(decoded_r: redis.Redis):
         await decoded_r.json().arrappend("non_existing_doc", "$..a")
 
 
-@pytest.mark.redismod
 async def test_arrlen_dollar(decoded_r: redis.Redis):
     await decoded_r.json().set(
         "doc1",
@@ -754,7 +721,6 @@ async def test_arrlen_dollar(decoded_r: redis.Redis):
     assert await decoded_r.json().arrlen("non_existing_doc", "..a") is None
 
 
-@pytest.mark.redismod
 async def test_arrpop_dollar(decoded_r: redis.Redis):
     await decoded_r.json().set(
         "doc1",
@@ -796,7 +762,6 @@ async def test_arrpop_dollar(decoded_r: redis.Redis):
         await decoded_r.json().arrpop("non_existing_doc", "..a")
 
 
-@pytest.mark.redismod
 async def test_arrtrim_dollar(decoded_r: redis.Redis):
     await decoded_r.json().set(
         "doc1",
@@ -848,7 +813,6 @@ async def test_arrtrim_dollar(decoded_r: redis.Redis):
         await decoded_r.json().arrtrim("non_existing_doc", "..a", 1, 1)
 
 
-@pytest.mark.redismod
 async def test_objkeys_dollar(decoded_r: redis.Redis):
     await decoded_r.json().set(
         "doc1",
@@ -878,7 +842,6 @@ async def test_objkeys_dollar(decoded_r: redis.Redis):
     assert await decoded_r.json().objkeys("doc1", "$..nowhere") == []
 
 
-@pytest.mark.redismod
 async def test_objlen_dollar(decoded_r: redis.Redis):
     await decoded_r.json().set(
         "doc1",
@@ -914,7 +877,6 @@ async def test_objlen_dollar(decoded_r: redis.Redis):
     await decoded_r.json().objlen("doc1", ".nowhere")
 
 
-@pytest.mark.redismod
 def load_types_data(nested_key_name):
     td = {
         "object": {},
@@ -934,7 +896,6 @@ def load_types_data(nested_key_name):
     return jdata, types
 
 
-@pytest.mark.redismod
 async def test_type_dollar(decoded_r: redis.Redis):
     jdata, jtypes = load_types_data("a")
     await decoded_r.json().set("doc1", "$", jdata)
@@ -953,7 +914,6 @@ async def test_type_dollar(decoded_r: redis.Redis):
     )
 
 
-@pytest.mark.redismod
 async def test_clear_dollar(decoded_r: redis.Redis):
     await decoded_r.json().set(
         "doc1",
@@ -1007,7 +967,6 @@ async def test_clear_dollar(decoded_r: redis.Redis):
         await decoded_r.json().clear("non_existing_doc", "$..a")
 
 
-@pytest.mark.redismod
 async def test_toggle_dollar(decoded_r: redis.Redis):
     await decoded_r.json().set(
         "doc1",
diff --git a/tests/test_asyncio/test_timeseries.py b/tests/test_asyncio/test_timeseries.py
--- a/tests/test_asyncio/test_timeseries.py
+++ b/tests/test_asyncio/test_timeseries.py
@@ -10,7 +10,6 @@
 )
 
 
-@pytest.mark.redismod
 async def test_create(decoded_r: redis.Redis):
     assert await decoded_r.ts().create(1)
     assert await decoded_r.ts().create(2, retention_msecs=5)
@@ -28,7 +27,6 @@ async def test_create(decoded_r: redis.Redis):
     assert_resp_response(decoded_r, 128, info.get("chunk_size"), info.get("chunkSize"))
 
 
-@pytest.mark.redismod
 @skip_ifmodversion_lt("1.4.0", "timeseries")
 async def test_create_duplicate_policy(decoded_r: redis.Redis):
     # Test for duplicate policy
@@ -44,7 +42,6 @@ async def test_create_duplicate_policy(decoded_r: redis.Redis):
         )
 
 
-@pytest.mark.redismod
 async def test_alter(decoded_r: redis.Redis):
     assert await decoded_r.ts().create(1)
     res = await decoded_r.ts().info(1)
@@ -67,7 +64,6 @@ async def test_alter(decoded_r: redis.Redis):
     )
 
 
-@pytest.mark.redismod
 @skip_ifmodversion_lt("1.4.0", "timeseries")
 async def test_alter_diplicate_policy(decoded_r: redis.Redis):
     assert await decoded_r.ts().create(1)
@@ -82,7 +78,6 @@ async def test_alter_diplicate_policy(decoded_r: redis.Redis):
     )
 
 
-@pytest.mark.redismod
 async def test_add(decoded_r: redis.Redis):
     assert 1 == await decoded_r.ts().add(1, 1, 1)
     assert 2 == await decoded_r.ts().add(2, 2, 3, retention_msecs=10)
@@ -105,7 +100,6 @@ async def test_add(decoded_r: redis.Redis):
     assert_resp_response(decoded_r, 128, info.get("chunk_size"), info.get("chunkSize"))
 
 
-@pytest.mark.redismod
 @skip_ifmodversion_lt("1.4.0", "timeseries")
 async def test_add_duplicate_policy(r: redis.Redis):
     # Test for duplicate policy BLOCK
@@ -146,7 +140,6 @@ async def test_add_duplicate_policy(r: redis.Redis):
     assert 5.0 == res[1]
 
 
-@pytest.mark.redismod
 async def test_madd(decoded_r: redis.Redis):
     await decoded_r.ts().create("a")
     assert [1, 2, 3] == await decoded_r.ts().madd(
@@ -154,7 +147,6 @@ async def test_madd(decoded_r: redis.Redis):
     )
 
 
-@pytest.mark.redismod
 async def test_incrby_decrby(decoded_r: redis.Redis):
     for _ in range(100):
         assert await decoded_r.ts().incrby(1, 1)
@@ -183,7 +175,6 @@ async def test_incrby_decrby(decoded_r: redis.Redis):
     assert_resp_response(decoded_r, 128, info.get("chunk_size"), info.get("chunkSize"))
 
 
-@pytest.mark.redismod
 async def test_create_and_delete_rule(decoded_r: redis.Redis):
     # test rule creation
     time = 100
@@ -207,7 +198,6 @@ async def test_create_and_delete_rule(decoded_r: redis.Redis):
     assert not info["rules"]
 
 
-@pytest.mark.redismod
 @skip_ifmodversion_lt("99.99.99", "timeseries")
 async def test_del_range(decoded_r: redis.Redis):
     try:
@@ -224,7 +214,6 @@ async def test_del_range(decoded_r: redis.Redis):
     )
 
 
-@pytest.mark.redismod
 async def test_range(r: redis.Redis):
     for i in range(100):
         await r.ts().add(1, i, i % 7)
@@ -239,7 +228,6 @@ async def test_range(r: redis.Redis):
     assert 10 == len(await r.ts().range(1, 0, 500, count=10))
 
 
-@pytest.mark.redismod
 @skip_ifmodversion_lt("99.99.99", "timeseries")
 async def test_range_advanced(decoded_r: redis.Redis):
     for i in range(100):
@@ -270,7 +258,6 @@ async def test_range_advanced(decoded_r: redis.Redis):
     assert_resp_response(decoded_r, res, [(0, 2.55), (10, 3.0)], [[0, 2.55], [10, 3.0]])
 
 
-@pytest.mark.redismod
 @skip_ifmodversion_lt("99.99.99", "timeseries")
 async def test_rev_range(decoded_r: redis.Redis):
     for i in range(100):
@@ -314,7 +301,6 @@ async def test_rev_range(decoded_r: redis.Redis):
     )
 
 
-@pytest.mark.redismod
 @pytest.mark.onlynoncluster
 async def test_multi_range(decoded_r: redis.Redis):
     await decoded_r.ts().create(1, labels={"Test": "This", "team": "ny"})
@@ -369,7 +355,6 @@ async def test_multi_range(decoded_r: redis.Redis):
         assert {"Test": "This", "team": "ny"} == res["1"][0]
 
 
-@pytest.mark.redismod
 @pytest.mark.onlynoncluster
 @skip_ifmodversion_lt("99.99.99", "timeseries")
 async def test_multi_range_advanced(decoded_r: redis.Redis):
@@ -487,7 +472,6 @@ async def test_multi_range_advanced(decoded_r: redis.Redis):
         assert [[0, 5.0], [5, 6.0]] == res["1"][2]
 
 
-@pytest.mark.redismod
 @pytest.mark.onlynoncluster
 @skip_ifmodversion_lt("99.99.99", "timeseries")
 async def test_multi_reverse_range(decoded_r: redis.Redis):
@@ -651,7 +635,6 @@ async def test_multi_reverse_range(decoded_r: redis.Redis):
         assert [[1, 10.0], [0, 1.0]] == res["1"][2]
 
 
-@pytest.mark.redismod
 async def test_get(decoded_r: redis.Redis):
     name = "test"
     await decoded_r.ts().create(name)
@@ -662,7 +645,6 @@ async def test_get(decoded_r: redis.Redis):
     assert 4 == (await decoded_r.ts().get(name))[1]
 
 
-@pytest.mark.redismod
 @pytest.mark.onlynoncluster
 async def test_mget(decoded_r: redis.Redis):
     await decoded_r.ts().create(1, labels={"Test": "This"})
@@ -698,7 +680,6 @@ async def test_mget(decoded_r: redis.Redis):
         assert {"Taste": "That", "Test": "This"} == res["2"][0]
 
 
-@pytest.mark.redismod
 async def test_info(decoded_r: redis.Redis):
     await decoded_r.ts().create(
         1, retention_msecs=5, labels={"currentLabel": "currentData"}
@@ -710,7 +691,6 @@ async def test_info(decoded_r: redis.Redis):
     assert info["labels"]["currentLabel"] == "currentData"
 
 
-@pytest.mark.redismod
 @skip_ifmodversion_lt("1.4.0", "timeseries")
 async def testInfoDuplicatePolicy(decoded_r: redis.Redis):
     await decoded_r.ts().create(
@@ -728,7 +708,6 @@ async def testInfoDuplicatePolicy(decoded_r: redis.Redis):
     )
 
 
-@pytest.mark.redismod
 @pytest.mark.onlynoncluster
 async def test_query_index(decoded_r: redis.Redis):
     await decoded_r.ts().create(1, labels={"Test": "This"})
@@ -740,8 +719,7 @@ async def test_query_index(decoded_r: redis.Redis):
     )
 
 
-# @pytest.mark.redismod
-# async def test_pipeline(r: redis.Redis):
+# # async def test_pipeline(r: redis.Redis):
 #     pipeline = await r.ts().pipeline()
 #     pipeline.create("with_pipeline")
 #     for i in range(100):
@@ -754,7 +732,6 @@ async def test_query_index(decoded_r: redis.Redis):
 #     assert await r.ts().get("with_pipeline")[1] == 99 * 1.1
 
 
-@pytest.mark.redismod
 async def test_uncompressed(decoded_r: redis.Redis):
     await decoded_r.ts().create("compressed")
     await decoded_r.ts().create("uncompressed", uncompressed=True)