diff --git a/docs/about/changelog.md b/docs/about/changelog.md
index fd89af3a..44c4aa38 100644
--- a/docs/about/changelog.md
+++ b/docs/about/changelog.md
@@ -9,7 +9,8 @@ description: Change log of all fakeredis releases
### 🚀 Features
-- Implement BITFIELD command #247
+- Implement `BITFIELD` command #247
+- Implement `COMMAND`, `COMMAND INFO`, `COMMAND COUNT` #248
## v2.19.0
diff --git a/docs/redis-commands/Redis.md b/docs/redis-commands/Redis.md
index 9c213f15..c25fb72c 100644
--- a/docs/redis-commands/Redis.md
+++ b/docs/redis-commands/Redis.md
@@ -1,11 +1,23 @@
# Redis commands
-## `server` commands (8/70 implemented)
+## `server` commands (11/70 implemented)
### [BGSAVE](https://redis.io/commands/bgsave/)
Asynchronously saves the database(s) to disk.
+### [COMMAND](https://redis.io/commands/command/)
+
+Returns detailed information about all commands.
+
+### [COMMAND COUNT](https://redis.io/commands/command-count/)
+
+Returns a count of commands.
+
+### [COMMAND INFO](https://redis.io/commands/command-info/)
+
+Returns information about one, multiple or all commands.
+
### [DBSIZE](https://redis.io/commands/dbsize/)
Returns the number of keys in the database.
@@ -94,14 +106,6 @@ Returns the authenticated username of the current connection.
Asynchronously rewrites the append-only file to disk.
-#### [COMMAND](https://redis.io/commands/command/) (not implemented)
-
-Returns detailed information about all commands.
-
-#### [COMMAND COUNT](https://redis.io/commands/command-count/) (not implemented)
-
-Returns a count of commands.
-
#### [COMMAND DOCS](https://redis.io/commands/command-docs/) (not implemented)
Returns documentary information about one, multiple or all commands.
@@ -114,10 +118,6 @@ Extracts the key names from an arbitrary command.
Extracts the key names and access flags for an arbitrary command.
-#### [COMMAND INFO](https://redis.io/commands/command-info/) (not implemented)
-
-Returns information about one, multiple or all commands.
-
#### [COMMAND LIST](https://redis.io/commands/command-list/) (not implemented)
Returns a list of command names.
@@ -625,7 +625,7 @@ Resets the connection.
Counts the number of set bits (population counting) in a string.
-#### [BITFIELD](https://redis.io/commands/bitfield/)
+### [BITFIELD](https://redis.io/commands/bitfield/)
Performs arbitrary bitfield integer operations on strings.
@@ -647,7 +647,7 @@ Sets or clears the bit at offset of the string value. Creates the key if it does
### Unsupported bitmap commands
-> To implement support for a command, see [here](../../guides/implement-command/)
+> To implement support for a command, see [here](../../guides/implement-command/)
#### [BITFIELD_RO](https://redis.io/commands/bitfield_ro/) (not implemented)
diff --git a/docs/requirements.txt b/docs/requirements.txt
index c417a30d..411fb777 100644
--- a/docs/requirements.txt
+++ b/docs/requirements.txt
@@ -1,2 +1,2 @@
mkdocs==1.5.3
-mkdocs-material==9.4.4
+mkdocs-material==9.4.6
diff --git a/fakeredis/commands.json b/fakeredis/commands.json
new file mode 100644
index 00000000..6bab40d9
--- /dev/null
+++ b/fakeredis/commands.json
@@ -0,0 +1 @@
+{"append": ["append", 3, ["write", "denyoom", "fast"], 1, 1, 1, ["@write", "@string", "@fast"], [], [], []], "bgsave": ["bgsave", -1, ["admin", "noscript", "no_async_loading"], 0, 0, 0, ["@admin", "@slow", "@dangerous"], [], [], []], "bitcount": ["bitcount", -2, ["readonly"], 1, 1, 1, ["@read", "@bitmap", "@slow"], [], [], []], "bitfield": ["bitfield", -2, ["write", "denyoom"], 1, 1, 1, ["@write", "@bitmap", "@slow"], [], [], []], "bitop": ["bitop", -4, ["write", "denyoom"], 2, 3, 1, ["@write", "@bitmap", "@slow"], [], [], []], "bitpos": ["bitpos", -3, ["readonly"], 1, 1, 1, ["@read", "@bitmap", "@slow"], [], [], []], "blmove": ["blmove", 6, ["write", "denyoom", "blocking"], 1, 2, 1, ["@write", "@list", "@slow", "@blocking"], [], [], []], "blmpop": ["blmpop", -5, ["write", "blocking", "movablekeys"], 2, 2, 1, ["@write", "@list", "@slow", "@blocking"], [], [], []], "blpop": ["blpop", -3, ["write", "blocking"], 1, 1, 1, ["@write", "@list", "@slow", "@blocking"], [], [], []], "brpop": ["brpop", -3, ["write", "blocking"], 1, 1, 1, ["@write", "@list", "@slow", "@blocking"], [], [], []], "brpoplpush": ["brpoplpush", 4, ["write", "denyoom", "blocking"], 1, 2, 1, ["@write", "@list", "@slow", "@blocking"], [], [], []], "bzmpop": ["bzmpop", -5, ["write", "blocking", "movablekeys"], 2, 2, 1, ["@write", "@sortedset", "@slow", "@blocking"], [], [], []], "bzpopmax": ["bzpopmax", -3, ["write", "blocking", "fast"], 1, 1, 1, ["@write", "@sortedset", "@fast", "@blocking"], [], [], []], "bzpopmin": ["bzpopmin", -3, ["write", "blocking", "fast"], 1, 1, 1, ["@write", "@sortedset", "@fast", "@blocking"], [], [], []], "command": ["command", -1, ["loading", "stale"], 0, 0, 0, ["@slow", "@connection"], [], [], []], "command count": ["command count", 2, ["loading", "stale"], 0, 0, 0, ["@slow", "@connection"], [], [], []], "command info": ["command info", -2, ["loading", "stale"], 0, 0, 0, ["@slow", "@connection"], [], [], []], "dbsize": ["dbsize", 1, ["readonly", "fast"], 0, 0, 0, ["@keyspace", "@read", "@fast"], [], [], []], "decr": ["decr", 2, ["write", "denyoom", "fast"], 1, 1, 1, ["@write", "@string", "@fast"], [], [], []], "decrby": ["decrby", 3, ["write", "denyoom", "fast"], 1, 1, 1, ["@write", "@string", "@fast"], [], [], []], "del": ["del", -2, ["write"], 1, 1, 1, ["@keyspace", "@write", "@slow"], [], [], []], "discard": ["discard", 1, ["noscript", "loading", "stale", "fast", "allow_busy"], 0, 0, 0, ["@fast", "@transaction"], [], [], []], "dump": ["dump", 2, ["readonly"], 1, 1, 1, ["@keyspace", "@read", "@slow"], [], [], []], "echo": ["echo", 2, ["loading", "stale", "fast"], 0, 0, 0, ["@fast", "@connection"], [], [], []], "eval": ["eval", -3, ["noscript", "stale", "skip_monitor", "no_mandatory_keys", "movablekeys"], 2, 2, 1, ["@slow", "@scripting"], [], [], []], "evalsha": ["evalsha", -3, ["noscript", "stale", "skip_monitor", "no_mandatory_keys", "movablekeys"], 2, 2, 1, ["@slow", "@scripting"], [], [], []], "exec": ["exec", 1, ["noscript", "loading", "stale", "skip_slowlog"], 0, 0, 0, ["@slow", "@transaction"], [], [], []], "exists": ["exists", -2, ["readonly", "fast"], 1, 1, 1, ["@keyspace", "@read", "@fast"], [], [], []], "expire": ["expire", -3, ["write", "fast"], 1, 1, 1, ["@keyspace", "@write", "@fast"], [], [], []], "expireat": ["expireat", -3, ["write", "fast"], 1, 1, 1, ["@keyspace", "@write", "@fast"], [], [], []], "flushall": ["flushall", -1, ["write"], 0, 0, 0, ["@keyspace", "@write", "@slow", "@dangerous"], [], [], []], "flushdb": ["flushdb", -1, ["write"], 0, 0, 0, ["@keyspace", "@write", "@slow", "@dangerous"], [], [], []], "geoadd": ["geoadd", -5, ["write", "denyoom"], 1, 1, 1, ["@write", "@geo", "@slow"], [], [], []], "geodist": ["geodist", -4, ["readonly"], 1, 1, 1, ["@read", "@geo", "@slow"], [], [], []], "geohash": ["geohash", -2, ["readonly"], 1, 1, 1, ["@read", "@geo", "@slow"], [], [], []], "geopos": ["geopos", -2, ["readonly"], 1, 1, 1, ["@read", "@geo", "@slow"], [], [], []], "georadius": ["georadius", -6, ["write", "denyoom", "movablekeys"], 1, 0, 1, ["@write", "@geo", "@slow"], [], [], []], "georadiusbymember": ["georadiusbymember", -5, ["write", "denyoom", "movablekeys"], 1, 0, 1, ["@write", "@geo", "@slow"], [], [], []], "georadiusbymember_ro": ["georadiusbymember_ro", -5, ["readonly"], 1, 1, 1, ["@read", "@geo", "@slow"], [], [], []], "georadius_ro": ["georadius_ro", -6, ["readonly"], 1, 1, 1, ["@read", "@geo", "@slow"], [], [], []], "geosearch": ["geosearch", -7, ["readonly"], 1, 1, 1, ["@read", "@geo", "@slow"], [], [], []], "geosearchstore": ["geosearchstore", -8, ["write", "denyoom"], 1, 2, 1, ["@write", "@geo", "@slow"], [], [], []], "get": ["get", 2, ["readonly", "fast"], 1, 1, 1, ["@read", "@string", "@fast"], [], [], []], "getbit": ["getbit", 3, ["readonly", "fast"], 1, 1, 1, ["@read", "@bitmap", "@fast"], [], [], []], "getdel": ["getdel", 2, ["write", "fast"], 1, 1, 1, ["@write", "@string", "@fast"], [], [], []], "getex": ["getex", -2, ["write", "fast"], 1, 1, 1, ["@write", "@string", "@fast"], [], [], []], "getrange": ["getrange", 4, ["readonly"], 1, 1, 1, ["@read", "@string", "@slow"], [], [], []], "getset": ["getset", 3, ["write", "denyoom", "fast"], 1, 1, 1, ["@write", "@string", "@fast"], [], [], []], "hdel": ["hdel", -3, ["write", "fast"], 1, 1, 1, ["@write", "@hash", "@fast"], [], [], []], "hexists": ["hexists", 3, ["readonly", "fast"], 1, 1, 1, ["@read", "@hash", "@fast"], [], [], []], "hget": ["hget", 3, ["readonly", "fast"], 1, 1, 1, ["@read", "@hash", "@fast"], [], [], []], "hgetall": ["hgetall", 2, ["readonly"], 1, 1, 1, ["@read", "@hash", "@slow"], [], [], []], "hincrby": ["hincrby", 4, ["write", "denyoom", "fast"], 1, 1, 1, ["@write", "@hash", "@fast"], [], [], []], "hincrbyfloat": ["hincrbyfloat", 4, ["write", "denyoom", "fast"], 1, 1, 1, ["@write", "@hash", "@fast"], [], [], []], "hkeys": ["hkeys", 2, ["readonly"], 1, 1, 1, ["@read", "@hash", "@slow"], [], [], []], "hlen": ["hlen", 2, ["readonly", "fast"], 1, 1, 1, ["@read", "@hash", "@fast"], [], [], []], "hmget": ["hmget", -3, ["readonly", "fast"], 1, 1, 1, ["@read", "@hash", "@fast"], [], [], []], "hmset": ["hmset", -4, ["write", "denyoom", "fast"], 1, 1, 1, ["@write", "@hash", "@fast"], [], [], []], "hrandfield": ["hrandfield", -2, ["readonly"], 1, 1, 1, ["@read", "@hash", "@slow"], [], [], []], "hscan": ["hscan", -3, ["readonly"], 1, 1, 1, ["@read", "@hash", "@slow"], [], [], []], "hset": ["hset", -4, ["write", "denyoom", "fast"], 1, 1, 1, ["@write", "@hash", "@fast"], [], [], []], "hsetnx": ["hsetnx", 4, ["write", "denyoom", "fast"], 1, 1, 1, ["@write", "@hash", "@fast"], [], [], []], "hstrlen": ["hstrlen", 3, ["readonly", "fast"], 1, 1, 1, ["@read", "@hash", "@fast"], [], [], []], "hvals": ["hvals", 2, ["readonly"], 1, 1, 1, ["@read", "@hash", "@slow"], [], [], []], "incr": ["incr", 2, ["write", "denyoom", "fast"], 1, 1, 1, ["@write", "@string", "@fast"], [], [], []], "incrby": ["incrby", 3, ["write", "denyoom", "fast"], 1, 1, 1, ["@write", "@string", "@fast"], [], [], []], "incrbyfloat": ["incrbyfloat", 3, ["write", "denyoom", "fast"], 1, 1, 1, ["@write", "@string", "@fast"], [], [], []], "keys": ["keys", 2, ["readonly"], 0, 0, 0, ["@keyspace", "@read", "@slow", "@dangerous"], [], [], []], "lastsave": ["lastsave", 1, ["loading", "stale", "fast"], 0, 0, 0, ["@admin", "@fast", "@dangerous"], [], [], []], "lcs": ["lcs", -3, ["readonly"], 1, 1, 1, ["@read", "@string", "@slow"], [], [], []], "lindex": ["lindex", 3, ["readonly"], 1, 1, 1, ["@read", "@list", "@slow"], [], [], []], "linsert": ["linsert", 5, ["write", "denyoom"], 1, 1, 1, ["@write", "@list", "@slow"], [], [], []], "llen": ["llen", 2, ["readonly", "fast"], 1, 1, 1, ["@read", "@list", "@fast"], [], [], []], "lmove": ["lmove", 5, ["write", "denyoom"], 1, 2, 1, ["@write", "@list", "@slow"], [], [], []], "lmpop": ["lmpop", -4, ["write", "movablekeys"], 1, 1, 1, ["@write", "@list", "@slow"], [], [], []], "lpop": ["lpop", -2, ["write", "fast"], 1, 1, 1, ["@write", "@list", "@fast"], [], [], []], "lpos": ["lpos", -3, ["readonly"], 1, 1, 1, ["@read", "@list", "@slow"], [], [], []], "lpush": ["lpush", -3, ["write", "denyoom", "fast"], 1, 1, 1, ["@write", "@list", "@fast"], [], [], []], "lpushx": ["lpushx", -3, ["write", "denyoom", "fast"], 1, 1, 1, ["@write", "@list", "@fast"], [], [], []], "lrange": ["lrange", 4, ["readonly"], 1, 1, 1, ["@read", "@list", "@slow"], [], [], []], "lrem": ["lrem", 4, ["write"], 1, 1, 1, ["@write", "@list", "@slow"], [], [], []], "lset": ["lset", 4, ["write", "denyoom"], 1, 1, 1, ["@write", "@list", "@slow"], [], [], []], "ltrim": ["ltrim", 4, ["write"], 1, 1, 1, ["@write", "@list", "@slow"], [], [], []], "mget": ["mget", -2, ["readonly", "fast"], 1, 1, 1, ["@read", "@string", "@fast"], [], [], []], "move": ["move", 3, ["write", "fast"], 1, 1, 1, ["@keyspace", "@write", "@fast"], [], [], []], "mset": ["mset", -3, ["write", "denyoom"], 1, 1, 2, ["@write", "@string", "@slow"], [], [], []], "msetnx": ["msetnx", -3, ["write", "denyoom"], 1, 1, 2, ["@write", "@string", "@slow"], [], [], []], "multi": ["multi", 1, ["noscript", "loading", "stale", "fast", "allow_busy"], 0, 0, 0, ["@fast", "@transaction"], [], [], []], "persist": ["persist", 2, ["write", "fast"], 1, 1, 1, ["@keyspace", "@write", "@fast"], [], [], []], "pexpire": ["pexpire", -3, ["write", "fast"], 1, 1, 1, ["@keyspace", "@write", "@fast"], [], [], []], "pexpireat": ["pexpireat", -3, ["write", "fast"], 1, 1, 1, ["@keyspace", "@write", "@fast"], [], [], []], "pfadd": ["pfadd", -2, ["write", "denyoom", "fast"], 1, 1, 1, ["@write", "@hyperloglog", "@fast"], [], [], []], "pfcount": ["pfcount", -2, ["readonly"], 1, 1, 1, ["@read", "@hyperloglog", "@slow"], [], [], []], "pfmerge": ["pfmerge", -2, ["write", "denyoom"], 1, 2, 1, ["@write", "@hyperloglog", "@slow"], [], [], []], "ping": ["ping", -1, ["fast"], 0, 0, 0, ["@fast", "@connection"], [], [], []], "psetex": ["psetex", 4, ["write", "denyoom"], 1, 1, 1, ["@write", "@string", "@slow"], [], [], []], "psubscribe": ["psubscribe", -2, ["pubsub", "noscript", "loading", "stale"], 0, 0, 0, ["@pubsub", "@slow"], [], [], []], "pttl": ["pttl", 2, ["readonly", "fast"], 1, 1, 1, ["@keyspace", "@read", "@fast"], [], [], []], "publish": ["publish", 3, ["pubsub", "loading", "stale", "fast"], 0, 0, 0, ["@pubsub", "@fast"], [], [], []], "pubsub": ["pubsub", -2, [], 0, 0, 0, ["@slow"], [], [], []], "pubsub channels": ["pubsub channels", -2, ["pubsub", "loading", "stale"], 0, 0, 0, ["@pubsub", "@slow"], [], [], []], "pubsub help": ["pubsub help", 2, ["loading", "stale"], 0, 0, 0, ["@slow"], [], [], []], "pubsub numpat": ["pubsub numpat", 2, ["pubsub", "loading", "stale"], 0, 0, 0, ["@pubsub", "@slow"], [], [], []], "pubsub numsub": ["pubsub numsub", -2, ["pubsub", "loading", "stale"], 0, 0, 0, ["@pubsub", "@slow"], [], [], []], "pubsub shardchannels": ["pubsub shardchannels", -2, ["pubsub", "loading", "stale"], 0, 0, 0, ["@pubsub", "@slow"], [], [], []], "pubsub shardnumsub": ["pubsub shardnumsub", -2, ["pubsub", "loading", "stale"], 0, 0, 0, ["@pubsub", "@slow"], [], [], []], "punsubscribe": ["punsubscribe", -1, ["pubsub", "noscript", "loading", "stale"], 0, 0, 0, ["@pubsub", "@slow"], [], [], []], "randomkey": ["randomkey", 1, ["readonly"], 0, 0, 0, ["@keyspace", "@read", "@slow"], [], [], []], "rename": ["rename", 3, ["write"], 1, 2, 1, ["@keyspace", "@write", "@slow"], [], [], []], "renamenx": ["renamenx", 3, ["write", "fast"], 1, 2, 1, ["@keyspace", "@write", "@fast"], [], [], []], "restore": ["restore", -4, ["write", "denyoom"], 1, 1, 1, ["@keyspace", "@write", "@slow", "@dangerous"], [], [], []], "rpop": ["rpop", -2, ["write", "fast"], 1, 1, 1, ["@write", "@list", "@fast"], [], [], []], "rpoplpush": ["rpoplpush", 3, ["write", "denyoom"], 1, 2, 1, ["@write", "@list", "@slow"], [], [], []], "rpush": ["rpush", -3, ["write", "denyoom", "fast"], 1, 1, 1, ["@write", "@list", "@fast"], [], [], []], "rpushx": ["rpushx", -3, ["write", "denyoom", "fast"], 1, 1, 1, ["@write", "@list", "@fast"], [], [], []], "sadd": ["sadd", -3, ["write", "denyoom", "fast"], 1, 1, 1, ["@write", "@set", "@fast"], [], [], []], "save": ["save", 1, ["admin", "noscript", "no_async_loading", "no_multi"], 0, 0, 0, ["@admin", "@slow", "@dangerous"], [], [], []], "scan": ["scan", -2, ["readonly"], 0, 0, 0, ["@keyspace", "@read", "@slow"], [], [], []], "scard": ["scard", 2, ["readonly", "fast"], 1, 1, 1, ["@read", "@set", "@fast"], [], [], []], "script": ["script", -2, [], 0, 0, 0, ["@slow"], [], [], []], "script exists": ["script exists", -3, ["noscript"], 0, 0, 0, ["@slow", "@scripting"], [], [], []], "script flush": ["script flush", -2, ["noscript"], 0, 0, 0, ["@slow", "@scripting"], [], [], []], "script help": ["script help", 2, ["loading", "stale"], 0, 0, 0, ["@slow", "@scripting"], [], [], []], "script load": ["script load", 3, ["noscript", "stale"], 0, 0, 0, ["@slow", "@scripting"], [], [], []], "sdiff": ["sdiff", -2, ["readonly"], 1, 1, 1, ["@read", "@set", "@slow"], [], [], []], "sdiffstore": ["sdiffstore", -3, ["write", "denyoom"], 1, 2, 1, ["@write", "@set", "@slow"], [], [], []], "select": ["select", 2, ["loading", "stale", "fast"], 0, 0, 0, ["@fast", "@connection"], [], [], []], "set": ["set", -3, ["write", "denyoom"], 1, 1, 1, ["@write", "@string", "@slow"], [], [], []], "setbit": ["setbit", 4, ["write", "denyoom"], 1, 1, 1, ["@write", "@bitmap", "@slow"], [], [], []], "setex": ["setex", 4, ["write", "denyoom"], 1, 1, 1, ["@write", "@string", "@slow"], [], [], []], "setnx": ["setnx", 3, ["write", "denyoom", "fast"], 1, 1, 1, ["@write", "@string", "@fast"], [], [], []], "setrange": ["setrange", 4, ["write", "denyoom"], 1, 1, 1, ["@write", "@string", "@slow"], [], [], []], "sinter": ["sinter", -2, ["readonly"], 1, 1, 1, ["@read", "@set", "@slow"], [], [], []], "sintercard": ["sintercard", -3, ["readonly", "movablekeys"], 1, 1, 1, ["@read", "@set", "@slow"], [], [], []], "sinterstore": ["sinterstore", -3, ["write", "denyoom"], 1, 2, 1, ["@write", "@set", "@slow"], [], [], []], "sismember": ["sismember", 3, ["readonly", "fast"], 1, 1, 1, ["@read", "@set", "@fast"], [], [], []], "smembers": ["smembers", 2, ["readonly"], 1, 1, 1, ["@read", "@set", "@slow"], [], [], []], "smismember": ["smismember", -3, ["readonly", "fast"], 1, 1, 1, ["@read", "@set", "@fast"], [], [], []], "smove": ["smove", 4, ["write", "fast"], 1, 2, 1, ["@write", "@set", "@fast"], [], [], []], "sort": ["sort", -2, ["write", "denyoom", "movablekeys"], 1, 0, 1, ["@write", "@set", "@sortedset", "@list", "@slow", "@dangerous"], [], [], []], "spop": ["spop", -2, ["write", "fast"], 1, 1, 1, ["@write", "@set", "@fast"], [], [], []], "spublish": ["spublish", 3, ["pubsub", "loading", "stale", "fast"], 1, 1, 1, ["@pubsub", "@fast"], [], [], []], "srandmember": ["srandmember", -2, ["readonly"], 1, 1, 1, ["@read", "@set", "@slow"], [], [], []], "srem": ["srem", -3, ["write", "fast"], 1, 1, 1, ["@write", "@set", "@fast"], [], [], []], "sscan": ["sscan", -3, ["readonly"], 1, 1, 1, ["@read", "@set", "@slow"], [], [], []], "ssubscribe": ["ssubscribe", -2, ["pubsub", "noscript", "loading", "stale"], 1, 1, 1, ["@pubsub", "@slow"], [], [], []], "strlen": ["strlen", 2, ["readonly", "fast"], 1, 1, 1, ["@read", "@string", "@fast"], [], [], []], "subscribe": ["subscribe", -2, ["pubsub", "noscript", "loading", "stale"], 0, 0, 0, ["@pubsub", "@slow"], [], [], []], "substr": ["substr", 4, ["readonly"], 1, 1, 1, ["@read", "@string", "@slow"], [], [], []], "sunion": ["sunion", -2, ["readonly"], 1, 1, 1, ["@read", "@set", "@slow"], [], [], []], "sunionstore": ["sunionstore", -3, ["write", "denyoom"], 1, 2, 1, ["@write", "@set", "@slow"], [], [], []], "sunsubscribe": ["sunsubscribe", -1, ["pubsub", "noscript", "loading", "stale"], 1, 1, 1, ["@pubsub", "@slow"], [], [], []], "swapdb": ["swapdb", 3, ["write", "fast"], 0, 0, 0, ["@keyspace", "@write", "@fast", "@dangerous"], [], [], []], "time": ["time", 1, ["loading", "stale", "fast"], 0, 0, 0, ["@fast"], [], [], []], "ttl": ["ttl", 2, ["readonly", "fast"], 1, 1, 1, ["@keyspace", "@read", "@fast"], [], [], []], "type": ["type", 2, ["readonly", "fast"], 1, 1, 1, ["@keyspace", "@read", "@fast"], [], [], []], "unlink": ["unlink", -2, ["write", "fast"], 1, 1, 1, ["@keyspace", "@write", "@fast"], [], [], []], "unsubscribe": ["unsubscribe", -1, ["pubsub", "noscript", "loading", "stale"], 0, 0, 0, ["@pubsub", "@slow"], [], [], []], "unwatch": ["unwatch", 1, ["noscript", "loading", "stale", "fast", "allow_busy"], 0, 0, 0, ["@fast", "@transaction"], [], [], []], "watch": ["watch", -2, ["noscript", "loading", "stale", "fast", "allow_busy"], 1, 1, 1, ["@fast", "@transaction"], [], [], []], "xack": ["xack", -4, ["write", "fast"], 1, 1, 1, ["@write", "@stream", "@fast"], [], [], []], "xadd": ["xadd", -5, ["write", "denyoom", "fast"], 1, 1, 1, ["@write", "@stream", "@fast"], [], [], []], "xautoclaim": ["xautoclaim", -6, ["write", "fast"], 1, 1, 1, ["@write", "@stream", "@fast"], [], [], []], "xclaim": ["xclaim", -6, ["write", "fast"], 1, 1, 1, ["@write", "@stream", "@fast"], [], [], []], "xdel": ["xdel", -3, ["write", "fast"], 1, 1, 1, ["@write", "@stream", "@fast"], [], [], []], "xgroup create": ["xgroup create", -5, ["write", "denyoom"], 2, 2, 1, ["@write", "@stream", "@slow"], [], [], []], "xgroup createconsumer": ["xgroup createconsumer", 5, ["write", "denyoom"], 2, 2, 1, ["@write", "@stream", "@slow"], [], [], []], "xgroup delconsumer": ["xgroup delconsumer", 5, ["write"], 2, 2, 1, ["@write", "@stream", "@slow"], [], [], []], "xgroup destroy": ["xgroup destroy", 4, ["write"], 2, 2, 1, ["@write", "@stream", "@slow"], [], [], []], "xgroup setid": ["xgroup setid", -5, ["write"], 2, 2, 1, ["@write", "@stream", "@slow"], [], [], []], "xinfo consumers": ["xinfo consumers", 4, ["readonly"], 2, 2, 1, ["@read", "@stream", "@slow"], [], [], []], "xinfo groups": ["xinfo groups", 3, ["readonly"], 2, 2, 1, ["@read", "@stream", "@slow"], [], [], []], "xinfo stream": ["xinfo stream", -3, ["readonly"], 2, 2, 1, ["@read", "@stream", "@slow"], [], [], []], "xlen": ["xlen", 2, ["readonly", "fast"], 1, 1, 1, ["@read", "@stream", "@fast"], [], [], []], "xpending": ["xpending", -3, ["readonly"], 1, 1, 1, ["@read", "@stream", "@slow"], [], [], []], "xrange": ["xrange", -4, ["readonly"], 1, 1, 1, ["@read", "@stream", "@slow"], [], [], []], "xread": ["xread", -4, ["readonly", "blocking", "movablekeys"], 0, 0, 1, ["@read", "@stream", "@slow", "@blocking"], [], [], []], "xreadgroup": ["xreadgroup", -7, ["write", "blocking", "movablekeys"], 0, 0, 1, ["@write", "@stream", "@slow", "@blocking"], [], [], []], "xrevrange": ["xrevrange", -4, ["readonly"], 1, 1, 1, ["@read", "@stream", "@slow"], [], [], []], "xtrim": ["xtrim", -4, ["write"], 1, 1, 1, ["@write", "@stream", "@slow"], [], [], []], "zadd": ["zadd", -4, ["write", "denyoom", "fast"], 1, 1, 1, ["@write", "@sortedset", "@fast"], [], [], []], "zcard": ["zcard", 2, ["readonly", "fast"], 1, 1, 1, ["@read", "@sortedset", "@fast"], [], [], []], "zcount": ["zcount", 4, ["readonly", "fast"], 1, 1, 1, ["@read", "@sortedset", "@fast"], [], [], []], "zdiff": ["zdiff", -3, ["readonly", "movablekeys"], 1, 1, 1, ["@read", "@sortedset", "@slow"], [], [], []], "zdiffstore": ["zdiffstore", -4, ["write", "denyoom", "movablekeys"], 1, 2, 1, ["@write", "@sortedset", "@slow"], [], [], []], "zincrby": ["zincrby", 4, ["write", "denyoom", "fast"], 1, 1, 1, ["@write", "@sortedset", "@fast"], [], [], []], "zinter": ["zinter", -3, ["readonly", "movablekeys"], 1, 1, 1, ["@read", "@sortedset", "@slow"], [], [], []], "zintercard": ["zintercard", -3, ["readonly", "movablekeys"], 1, 1, 1, ["@read", "@sortedset", "@slow"], [], [], []], "zinterstore": ["zinterstore", -4, ["write", "denyoom", "movablekeys"], 1, 2, 1, ["@write", "@sortedset", "@slow"], [], [], []], "zlexcount": ["zlexcount", 4, ["readonly", "fast"], 1, 1, 1, ["@read", "@sortedset", "@fast"], [], [], []], "zmpop": ["zmpop", -4, ["write", "movablekeys"], 1, 1, 1, ["@write", "@sortedset", "@slow"], [], [], []], "zmscore": ["zmscore", -3, ["readonly", "fast"], 1, 1, 1, ["@read", "@sortedset", "@fast"], [], [], []], "zpopmax": ["zpopmax", -2, ["write", "fast"], 1, 1, 1, ["@write", "@sortedset", "@fast"], [], [], []], "zpopmin": ["zpopmin", -2, ["write", "fast"], 1, 1, 1, ["@write", "@sortedset", "@fast"], [], [], []], "zrandmember": ["zrandmember", -2, ["readonly"], 1, 1, 1, ["@read", "@sortedset", "@slow"], [], [], []], "zrange": ["zrange", -4, ["readonly"], 1, 1, 1, ["@read", "@sortedset", "@slow"], [], [], []], "zrangebylex": ["zrangebylex", -4, ["readonly"], 1, 1, 1, ["@read", "@sortedset", "@slow"], [], [], []], "zrangebyscore": ["zrangebyscore", -4, ["readonly"], 1, 1, 1, ["@read", "@sortedset", "@slow"], [], [], []], "zrangestore": ["zrangestore", -5, ["write", "denyoom"], 1, 2, 1, ["@write", "@sortedset", "@slow"], [], [], []], "zrank": ["zrank", -3, ["readonly", "fast"], 1, 1, 1, ["@read", "@sortedset", "@fast"], [], [], []], "zrem": ["zrem", -3, ["write", "fast"], 1, 1, 1, ["@write", "@sortedset", "@fast"], [], [], []], "zremrangebylex": ["zremrangebylex", 4, ["write"], 1, 1, 1, ["@write", "@sortedset", "@slow"], [], [], []], "zremrangebyrank": ["zremrangebyrank", 4, ["write"], 1, 1, 1, ["@write", "@sortedset", "@slow"], [], [], []], "zremrangebyscore": ["zremrangebyscore", 4, ["write"], 1, 1, 1, ["@write", "@sortedset", "@slow"], [], [], []], "zrevrange": ["zrevrange", -4, ["readonly"], 1, 1, 1, ["@read", "@sortedset", "@slow"], [], [], []], "zrevrangebylex": ["zrevrangebylex", -4, ["readonly"], 1, 1, 1, ["@read", "@sortedset", "@slow"], [], [], []], "zrevrangebyscore": ["zrevrangebyscore", -4, ["readonly"], 1, 1, 1, ["@read", "@sortedset", "@slow"], [], [], []], "zrevrank": ["zrevrank", -3, ["readonly", "fast"], 1, 1, 1, ["@read", "@sortedset", "@fast"], [], [], []], "zscan": ["zscan", -3, ["readonly"], 1, 1, 1, ["@read", "@sortedset", "@slow"], [], [], []], "zscore": ["zscore", 3, ["readonly", "fast"], 1, 1, 1, ["@read", "@sortedset", "@fast"], [], [], []], "zunion": ["zunion", -3, ["readonly", "movablekeys"], 1, 1, 1, ["@read", "@sortedset", "@slow"], [], [], []], "zunionstore": ["zunionstore", -4, ["write", "denyoom", "movablekeys"], 1, 2, 1, ["@write", "@sortedset", "@slow"], [], [], []], "json.del": ["json.del", -1, [], 0, 0, 0, [], [], [], []], "json.forget": ["json.forget", -1, [], 0, 0, 0, [], [], [], []], "json.get": ["json.get", -1, [], 0, 0, 0, [], [], [], []], "json.toggle": ["json.toggle", -1, [], 0, 0, 0, [], [], [], []], "json.clear": ["json.clear", -1, [], 0, 0, 0, [], [], [], []], "json.set": ["json.set", -1, [], 0, 0, 0, [], [], [], []], "json.mset": ["json.mset", -1, [], 0, 0, 0, [], [], [], []], "json.merge": ["json.merge", -1, [], 0, 0, 0, [], [], [], []], "json.mget": ["json.mget", -1, [], 0, 0, 0, [], [], [], []], "json.numincrby": ["json.numincrby", -1, [], 0, 0, 0, [], [], [], []], "json.nummultby": ["json.nummultby", -1, [], 0, 0, 0, [], [], [], []], "json.strappend": ["json.strappend", -1, [], 0, 0, 0, [], [], [], []], "json.strlen": ["json.strlen", -1, [], 0, 0, 0, [], [], [], []], "json.arrappend": ["json.arrappend", -1, [], 0, 0, 0, [], [], [], []], "json.arrindex": ["json.arrindex", -1, [], 0, 0, 0, [], [], [], []], "json.arrinsert": ["json.arrinsert", -1, [], 0, 0, 0, [], [], [], []], "json.arrlen": ["json.arrlen", -1, [], 0, 0, 0, [], [], [], []], "json.arrpop": ["json.arrpop", -1, [], 0, 0, 0, [], [], [], []], "json.arrtrim": ["json.arrtrim", -1, [], 0, 0, 0, [], [], [], []], "json.objkeys": ["json.objkeys", -1, [], 0, 0, 0, [], [], [], []], "json.objlen": ["json.objlen", -1, [], 0, 0, 0, [], [], [], []], "json.type": ["json.type", -1, [], 0, 0, 0, [], [], [], []], "bf.reserve": ["bf.reserve", -1, [], 0, 0, 0, [], [], [], []], "bf.add": ["bf.add", -1, [], 0, 0, 0, [], [], [], []], "bf.madd": ["bf.madd", -1, [], 0, 0, 0, [], [], [], []], "bf.insert": ["bf.insert", -1, [], 0, 0, 0, [], [], [], []], "bf.exists": ["bf.exists", -1, [], 0, 0, 0, [], [], [], []], "bf.mexists": ["bf.mexists", -1, [], 0, 0, 0, [], [], [], []], "bf.scandump": ["bf.scandump", -1, [], 0, 0, 0, [], [], [], []], "bf.loadchunk": ["bf.loadchunk", -1, [], 0, 0, 0, [], [], [], []], "bf.info": ["bf.info", -1, [], 0, 0, 0, [], [], [], []], "bf.card": ["bf.card", -1, [], 0, 0, 0, [], [], [], []]}
\ No newline at end of file
diff --git a/fakeredis/commands_mixins/server_mixin.py b/fakeredis/commands_mixins/server_mixin.py
index 8a49d655..e5ad715d 100644
--- a/fakeredis/commands_mixins/server_mixin.py
+++ b/fakeredis/commands_mixins/server_mixin.py
@@ -1,15 +1,43 @@
+import json
+import os
import time
-from typing import Any
+from typing import Any, List, Optional, Dict
from fakeredis import _msgs as msgs
-from fakeredis._commands import command, DbIndex
+from fakeredis._commands import command, DbIndex, SUPPORTED_COMMANDS
from fakeredis._helpers import OK, SimpleError, casematch, BGSAVE_STARTED, Database
+_COMMAND_INFO: Dict[bytes, List[Any]] = None
+
+
+def convert_obj(obj: Any) -> Any:
+ if isinstance(obj, str):
+ return obj.encode()
+ if isinstance(obj, list):
+ return [convert_obj(x) for x in obj]
+ if isinstance(obj, dict):
+ return {convert_obj(k): convert_obj(obj[k]) for k in obj}
+ return obj
+
+
+def _load_command_info() -> None:
+ global _COMMAND_INFO
+ if _COMMAND_INFO is None:
+ with open(os.path.join(os.path.dirname(__file__), '..', 'commands.json')) as f:
+ _COMMAND_INFO = convert_obj(json.load(f))
+
class ServerCommandsMixin:
_server: Any
_db: Database
+ @staticmethod
+ def _get_command_info(cmd: str) -> Optional[List[Any]]:
+ _load_command_info()
+ if cmd not in SUPPORTED_COMMANDS or cmd.encode() not in _COMMAND_INFO:
+ return None
+ return _COMMAND_INFO[cmd.encode()]
+
@command((), (bytes,), flags=msgs.FLAG_NO_SCRIPT)
def bgsave(self, *args):
if len(args) > 1 or (len(args) == 1 and not casematch(args[0], b"schedule")):
@@ -60,3 +88,19 @@ def swapdb(self, index1, index2):
db2 = self._server.dbs[index2]
db1.swap(db2)
return OK
+
+ @command(name="COMMAND INFO", fixed=(), repeat=(bytes,))
+ def command_info(self, *commands):
+ res = [self._get_command_info(cmd) for cmd in commands]
+ return res
+
+ @command(name="COMMAND COUNT", fixed=(), repeat=())
+ def command_count(self):
+ _load_command_info()
+ return len(_COMMAND_INFO)
+
+ @command(name="COMMAND", fixed=(), repeat=())
+ def command(self):
+ _load_command_info()
+ res = [self._get_command_info(cmd.decode()) for cmd in _COMMAND_INFO]
+ return res
diff --git a/scripts/create_issues.py b/scripts/create_issues.py
index 93443ebd..6c07003d 100644
--- a/scripts/create_issues.py
+++ b/scripts/create_issues.py
@@ -5,15 +5,17 @@
- Set environment variable `GITHUB_TOKEN` to a github token with permissions to create issues.
- Another option is to create `.env` file with `GITHUB_TOKEN`.
"""
+import json
import os
+import requests
from dotenv import load_dotenv
from github import Github
-from supported import download_redis_commands, implemented_commands
-
load_dotenv() # take environment variables from .env.
+THIS_DIR = os.path.join(os.path.dirname(os.path.abspath(__file__)))
+
IGNORE_GROUPS = {
'suggestion', 'tdigest', 'scripting', 'cf', 'topk',
'hyperloglog', 'graph', 'timeseries', 'connection',
@@ -48,8 +50,22 @@ def commands_groups(
return implemented, unimplemented
+def download_redis_commands() -> dict:
+ from supported2 import METADATA
+ cmds = {}
+ for filename, url in METADATA:
+ full_filename = os.path.join(THIS_DIR, filename)
+ if not os.path.exists(full_filename):
+ contents = requests.get(url).content
+ open(full_filename, 'wb').write(contents)
+ curr_cmds = json.load(open(full_filename))
+ cmds = cmds | {k.lower(): v for k, v in curr_cmds.items()}
+ return cmds
+
+
def get_unimplemented_and_implemented_commands() -> tuple[dict[str, list[str]], dict[str, list[str]]]:
"""Returns 2 dictionaries, one of unimplemented commands and another of implemented commands"""
+ from supported2 import implemented_commands
commands = download_redis_commands()
implemented_commands_set = implemented_commands()
implemented_dict, unimplemented_dict = commands_groups(commands, implemented_commands_set)
diff --git a/scripts/generate_command_info.py b/scripts/generate_command_info.py
new file mode 100644
index 00000000..a2349caf
--- /dev/null
+++ b/scripts/generate_command_info.py
@@ -0,0 +1,105 @@
+import json
+import os
+from collections import namedtuple
+from typing import Any, List, Dict
+
+import requests
+
+from fakeredis._commands import SUPPORTED_COMMANDS
+
+THIS_DIR = os.path.join(os.path.dirname(os.path.abspath(__file__)))
+CommandsMeta = namedtuple('CommandsMeta', ['local_filename', 'stack', 'title', 'url', ])
+METADATA = [
+ CommandsMeta('.commands.json', 'Redis', 'Redis',
+ 'https://raw.githubusercontent.com/redis/redis-doc/master/commands.json', ),
+ CommandsMeta('.json.commands.json', 'RedisJson', 'JSON',
+ 'https://raw.githubusercontent.com/RedisJSON/RedisJSON/master/commands.json', ),
+ CommandsMeta('.graph.commands.json', 'RedisGraph', 'Graph',
+ 'https://raw.githubusercontent.com/RedisGraph/RedisGraph/master/commands.json', ),
+ CommandsMeta('.ts.commands.json', 'RedisTimeSeries', 'Time Series',
+ 'https://raw.githubusercontent.com/RedisTimeSeries/RedisTimeSeries/master/commands.json', ),
+ CommandsMeta('.ft.commands.json', 'RedisSearch', 'Search',
+ 'https://raw.githubusercontent.com/RediSearch/RediSearch/master/commands.json', ),
+ CommandsMeta('.bloom.commands.json', 'RedisBloom', 'Probabilistic',
+ 'https://raw.githubusercontent.com/RedisBloom/RedisBloom/master/commands.json', ),
+]
+
+
+def download_single_stack_commands(filename, url) -> dict:
+ full_filename = os.path.join(THIS_DIR, filename)
+ if not os.path.exists(full_filename):
+ contents = requests.get(url).content
+ open(full_filename, 'wb').write(contents)
+ curr_cmds = json.load(open(full_filename))
+ cmds = {k.lower(): v for k, v in curr_cmds.items()}
+ return cmds
+
+
+def implemented_commands() -> set:
+ res = set(SUPPORTED_COMMANDS.keys())
+ if 'json.type' not in res:
+ raise ValueError('Make sure jsonpath_ng is installed to get accurate documentation')
+ return res
+
+
+def dict_deep_get(d: Dict[Any, Any], *keys, default_value: Any = None) -> Any:
+ res = d
+ for key in keys:
+ if isinstance(res, list) and isinstance(key, int):
+ res = res[key]
+ else:
+ res = res.get(key, None)
+ if res is None:
+ return default_value
+ return default_value if res is None else res
+
+
+def key_specs_array(cmd_info: Dict[str, Any]) -> List[Any]:
+ return []
+
+
+def get_command_info(cmd_name: str, cmd_info: Dict[str, Any]) -> List[Any]:
+ """Returns a list
+ 1 Name //
+ 2 Arity //
+ 3 Flags //
+ 4 First key //
+ 5 Last key //
+ 6 Step //
+ 7 ACL categories (as of Redis 6.0) //
+ 8 Tips (as of Redis 7.0) //
+ 9 Key specifications (as of Redis 7.0)
+ 10 Subcommands (as of Redis 7.0)
+ """
+ first_key = dict_deep_get(cmd_info, 'key_specs', 0, 'begin_search', 'spec', 'index', default_value=0)
+ last_key = dict_deep_get(cmd_info, 'key_specs', -1, 'begin_search', 'spec', 'index', default_value=0)
+ step = dict_deep_get(cmd_info, 'key_specs', 0, 'find_keys', 'spec', 'keystep', default_value=0)
+ tips = [] # todo
+ subcommands = [] # todo
+ res = [
+ cmd_name.lower(),
+ cmd_info.get("arity", -1),
+ cmd_info.get("command_flags", []),
+ first_key,
+ last_key,
+ step,
+ cmd_info.get("acl_categories", []),
+ tips,
+ key_specs_array(cmd_info),
+ subcommands,
+ ]
+ return res
+
+
+if __name__ == '__main__':
+ implemented = implemented_commands()
+ command_info_dict: Dict[str, List[Any]] = dict()
+ for cmd_meta in METADATA:
+ cmds = download_single_stack_commands(cmd_meta.local_filename, cmd_meta.url)
+ for cmd in cmds:
+ if cmd not in implemented:
+ continue
+ command_info_dict[cmd] = get_command_info(cmd, cmds[cmd])
+ print(command_info_dict[cmd])
+ with open(os.path.join(os.path.dirname(__file__), '..', 'fakeredis', 'commands.json'), 'w') as f:
+ json.dump(command_info_dict, f)
diff --git a/scripts/supported.py b/scripts/supported.py
deleted file mode 100755
index ed10d201..00000000
--- a/scripts/supported.py
+++ /dev/null
@@ -1,104 +0,0 @@
-import json
-import os
-
-import requests
-
-from fakeredis._commands import SUPPORTED_COMMANDS
-
-THIS_DIR = os.path.join(os.path.dirname(os.path.abspath(__file__)))
-COMMAND_FILES = [
- ('.commands.json', 'https://raw.githubusercontent.com/redis/redis-doc/master/commands.json'),
- ('.json.commands.json', 'https://raw.githubusercontent.com/RedisJSON/RedisJSON/master/commands.json'),
- ('.graph.commands.json', 'https://raw.githubusercontent.com/RedisGraph/RedisGraph/master/commands.json'),
- ('.ts.commands.json', 'https://raw.githubusercontent.com/RedisTimeSeries/RedisTimeSeries/master/commands.json'),
- ('.ft.commands.json', 'https://raw.githubusercontent.com/RediSearch/RediSearch/master/commands.json'),
- ('.bloom.commands.json', 'https://raw.githubusercontent.com/RedisBloom/RedisBloom/master/commands.json'),
-]
-
-TARGET_FILES = {
- 'unimplemented': 'docs/redis-commands/unimplemented_commands.md',
- 'implemented': 'docs/redis-commands/implemented_commands.md',
-}
-
-
-def download_redis_commands() -> dict:
- cmds = {}
- for filename, url in COMMAND_FILES:
- full_filename = os.path.join(THIS_DIR, filename)
- if not os.path.exists(full_filename):
- contents = requests.get(url).content
- open(full_filename, 'wb').write(contents)
- curr_cmds = json.load(open(full_filename))
- cmds = cmds | {k.lower(): v for k, v in curr_cmds.items()}
- return cmds
-
-
-def implemented_commands() -> set:
- res = set(SUPPORTED_COMMANDS.keys())
- if 'json.type' not in res:
- raise ValueError('Make sure jsonpath_ng is installed to get accurate documenentation')
- return res
-
-
-def commands_groups(
- all_commands: dict, implemented_set: set
-) -> tuple[dict[str, list[str]], dict[str, list[str]]]:
- implemented, unimplemented = dict(), dict()
- for cmd in all_commands:
- group = all_commands[cmd]['group']
- unimplemented.setdefault(group, [])
- implemented.setdefault(group, [])
- if cmd in implemented_set:
- implemented[group].append(cmd)
- else:
- unimplemented[group].append(cmd)
- return implemented, unimplemented
-
-
-def generate_markdown_files(
- all_commands: dict,
- unimplemented: dict,
- implemented: dict) -> None:
- def print_groups(dictionary: dict, f):
- for group in dictionary:
- f.write(f'## {group} commands\n\n')
- for cmd in dictionary[group]:
- f.write(f"### [{cmd.upper()}](https://redis.io/commands/{cmd.replace(' ', '-')}/)\n\n")
- f.write(f"{all_commands[cmd]['summary']}\n\n")
- f.write("\n")
-
- supported_commands_file = open(TARGET_FILES['implemented'], 'w')
- supported_commands_file.write("""# Supported commands
-
-Here is a list of all redis [implemented commands](#implemented-commands) and a
-list of [unimplemented commands](#unimplemented-commands).
-
-------\n\n
-""")
- print_groups(implemented, supported_commands_file)
-
- unimplemented_cmds_file = open(TARGET_FILES['unimplemented'], 'w')
- unimplemented_cmds_file.write("""# Unimplemented Commands
-All the redis commands are implemented in fakeredis with these exceptions:\n\n""")
- print_groups(unimplemented, unimplemented_cmds_file)
-
-
-def get_unimplemented_and_implemented_commands() -> tuple[dict[str, list[str]], dict[str, list[str]]]:
- """Returns 2 dictionaries, one of unimplemented commands and another of implemented commands
-
- """
- commands = download_redis_commands()
- implemented_commands_set = implemented_commands()
- implemented_dict, unimplemented_dict = commands_groups(commands, implemented_commands_set)
- groups = sorted(implemented_dict.keys(), key=lambda x: len(unimplemented_dict[x]))
- for group in groups:
- unimplemented_count = len(unimplemented_dict[group])
- total_count = len(implemented_dict.get(group)) + unimplemented_count
- print(f'{group} has {unimplemented_count}/{total_count} unimplemented commands')
- return unimplemented_dict, implemented_dict
-
-
-if __name__ == '__main__':
- commands = download_redis_commands()
- unimplemented_dict, implemented_dict = get_unimplemented_and_implemented_commands()
- generate_markdown_files(commands, unimplemented_dict, implemented_dict)
diff --git a/test/test_mixins/test_server_commands.py b/test/test_mixins/test_server_commands.py
index 4497b405..f0badcaf 100644
--- a/test/test_mixins/test_server_commands.py
+++ b/test/test_mixins/test_server_commands.py
@@ -5,6 +5,8 @@
import redis
from redis.exceptions import ResponseError
+from fakeredis._commands import SUPPORTED_COMMANDS
+
def test_swapdb(r, create_redis):
r1 = create_redis(1)
@@ -41,6 +43,16 @@ def test_lastsave(r: redis.Redis):
assert isinstance(r.lastsave(), datetime)
+def test_command(r: redis.Redis):
+ commands_dict = r.command()
+ one_word_commands = {cmd for cmd in SUPPORTED_COMMANDS if ' ' not in cmd}
+ assert one_word_commands - set(commands_dict.keys()) == set()
+
+
+def test_command_info(r: redis.Redis):
+ assert r.command_count() >= len(SUPPORTED_COMMANDS)
+
+
@pytest.mark.slow
def test_bgsave_timestamp_update(r: redis.Redis):
early_timestamp = r.lastsave()