RedisJSON / redisjson-py

An extension to redis-py for using Redis' ReJSON module
https://redisjson.io
BSD 2-Clause "Simplified" License
160 stars 34 forks source link

TypeError when executing jsonget with pipeline for key that does not exist #44

Closed mnoop closed 3 years ago

mnoop commented 3 years ago

If you execute jsonget on the Client and the key does not exist, it will catch the TypeError and instead return None, as expected.

If you execute jsonget on a pipeline and the key does not exist, it will throw the TypeError that results from json decoding the None value. Because of this, I cannot get any of the other results from the other commands from the pipeline.

Python 3.6.9 rejson 0.5.4

Traceback (most recent call last):
  File "test.py", line 7, in <module>
    result = pipeline.execute()
  File "/home/user/.local/lib/python3.6/site-packages/redis/client.py", line 4019, in execute
    return execute(conn, stack, raise_on_error)
  File "/home/user/.local/lib/python3.6/site-packages/redis/client.py", line 3943, in _execute_transaction
    r = self.response_callbacks[command_name](r, **options)
  File "/usr/lib/python3.6/json/decoder.py", line 339, in decode
    obj, end = self.raw_decode(s, idx=_w(s, 0).end())
TypeError: expected string or bytes-like object
import rejson

rj = rejson.Client(host='localhost', port=6379, decode_responses=True)

pipeline = rj.pipeline()
pipeline.jsonget("gdrbhiserbgherigh")
result = pipeline.execute()
bentsku commented 3 years ago

Hello,

Yes, this is a known problem. We got a workaround for the JSON.GET command, but not implemented for others. I guess we should rework the decoding implementation to take care of this specific instance.

There is however a quick fix for your problem: a custom JSON decoder. You can implement it by passing it to your ReJSON client instance.

import json
from rejson import Client

class CustomDecoder(json.JSONDecoder):
    def decode(self, s: str, *args, **kwargs):
        try:
            return json.JSONDecoder.decode(self, s, *args, **kwargs)
        except TypeError:
            if s is not None:
                raise
            return None

decoder = CustomDecoder()

rj = Client(host='localhost', port=6379, decode_responses=True, decoder=decoder)

This will catch all None values coming back from ReJSON and return them correctly, in any JSON.* commands.

oshadmi commented 3 years ago

fixed by #46