jamesls/fakeredis

TypeError: hset() got an unexpected keyword argument 'mapping'

beheh opened this issue · 6 comments

beheh commented

As per redis-py's CHANGES as of 3.5.0 hset now accepts multiple keys at once, deprecating hmset. This is implemented through the backwards-compatible signature:

def hset(self, name, key=None, value=None, mapping=None)

Though on fakeredis 1.4.1, explicitly specifying the mapping kwarg through code like

redis.hset("key", mapping={"a": "val1", "b": "val2"})

fails with

TypeError: hset() got an unexpected keyword argument 'mapping'

I tried to build a pull request but I found the magic @command handling very confusing and hard to work with.

Are you sure you're actually using redis-py 3.5? The hset method on a FakeRedis object is simply inherited from the Redis object, so it looks like you're running an older redis version. Fakeredis should already support multi-element HSET.

beheh commented

This started happening to me after I upgraded my redis-py to 3.5, and then as per it's changelog migrated from hmset to hset.

The signature of hset in redis-py 3.5 is what I put in the initial comment: https://github.com/andymccurdy/redis-py/blob/a9347cd0bc3c361cbdf4af6811ee465211eabdb0/redis/client.py#L3034-L3050

As I want to set multiple elements from my code at once, I'm therefore explicitly calling

redis.hset("key", mapping={"a": "val1", "b": "val2"})

...notice the kwarg mapping. That's what fakeredis can't handle, the kwarg. I also cannot use

redis.hset("key", {"a": "val1", "b": "val2"})

...because while that might work in fakeredis, the real redis-py assumes that's my key argument, as per the signature above.

The workaround for now is to continue using hmset, but that is deprecated and to me it just looks like fakeredis needs updating to be compatible with the latest redis-py API here.

It's working for me:

In [1]: import fakeredis                                                        

In [2]: r=fakeredis.FakeRedis()                                                 

In [3]: r.hset("key", mapping={"a": "val1", "b": "val2"})                       
Out[3]: 2

Please post the output of the following:

import redis, fakeredis
redis.__version__
fakeredis.__version__
beheh commented

I see, I was using redis-py 3.3. Looking at the fakeredis code then it was unclear to me how that could possibly work without updating the fakeredis signature, but I guess that's the whole @command stuff doing it's thing. Thanks for the fast response!

fakeredis implements the redis wire protocol (well, sort of) - so FakeRedis.hset is Redis.hset (by inheritance), and the code you're pointing at is what fakeredis implements after redis encodes and fakeredis decodes the wire protocol.

beheh commented

I see - thanks for the clarification!