Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion rejson/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -120,6 +120,6 @@ def decode(self, obj):
obj = rj.jsonget('custom', Path.rootPath())
```
"""
__version__ = "0.5.4"
__version__ = "0.6.0-alpha"
from .client import Client
from .path import Path
61 changes: 56 additions & 5 deletions rejson/client.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import six
import json
from redis import StrictRedis
import redis.client as rc
from redis.client import Pipeline
from redis._compat import (long, nativestr)
from .path import Path
Expand All @@ -24,7 +25,7 @@ def _f(b):
return _f


class Client(StrictRedis):
class Client():
"""
This class subclasses redis-py's `StrictRedis` and implements ReJSON's
commmands (prefixed with "json").
Expand All @@ -37,8 +38,9 @@ class Client(StrictRedis):
_encode = None
_decoder = None
_decode = None
_client = None

def __init__(self, encoder=None, decoder=None, *args, **kwargs):
def __init__(self, client=None, encoder=None, decoder=None, *args, **kwargs):
"""
Creates a new ReJSON client.

Expand All @@ -47,7 +49,10 @@ def __init__(self, encoder=None, decoder=None, *args, **kwargs):
"""
self.setEncoder(encoder)
self.setDecoder(decoder)
StrictRedis.__init__(self, *args, **kwargs)
if client is None:
self.setClient(StrictRedis(*args, **kwargs))
else:
self.setClient(client)

# Set the module commands' callbacks
MODULE_CALLBACKS = {
Expand All @@ -68,8 +73,47 @@ def __init__(self, encoder=None, decoder=None, *args, **kwargs):
'JSON.OBJLEN': long,
}
for k, v in six.iteritems(MODULE_CALLBACKS):
self.set_response_callback(k, v)

self.client.set_response_callback(k, v)

#######################################################################
# TODO - see if this pass-through stuff can be simplified
@property
def client(self):
return self._client

def execute_command(self, *args, **kwargs):

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@radoye why not creating a decorator for all the client functions?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sure. I'm happy to clean up once it's ready for merging.

  1. Let's figure out if tests make sense, or I overlooked something.
  2. Except for hiding these trivial functions with a decorator, any other approach comments?

return self.client.execute_command(*args, **kwargs)

def exists(self, *args, **kwargs):
return self.client.exists(*args, **kwargs)

def get(self, *args, **kwargs):
return self.client.get(*args, **kwargs)

@property
def connection_pool(self):
return self.client.connection_pool

@connection_pool.setter
def connection_pool(self, new_value):
self.client.connection_pool = new_value

@property
def response_callbacks(self):
return self.client.response_callbacks

@response_callbacks.setter
def response_callbacks(self, new_value):
self.client.response_callbacks = new_value

def flushdb(self):
self.client.flushdb()

#######################################################################

def setClient(self, client):
self._client = client

def setEncoder(self, encoder):
"""
Sets the client's encoder
Expand Down Expand Up @@ -258,6 +302,7 @@ def pipeline(self, transaction=True, shard_hint=None):
Overridden in order to provide the right client through the pipeline.
"""
p = Pipeline(
client=self.client,
connection_pool=self.connection_pool,
response_callbacks=self.response_callbacks,
transaction=transaction,
Expand All @@ -266,5 +311,11 @@ def pipeline(self, transaction=True, shard_hint=None):
p.setDecoder(self._decoder)
return p


class Pipeline(Pipeline, Client):
"Pipeline for ReJSONClient"

def __init__(self, client=None, *args, **kwargs):
Client.__init__(self, client=client)
rc.Pipeline.__init__(self, *args, **kwargs)

23 changes: 19 additions & 4 deletions tests/test_rejson.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import os
import six
import json
import unittest
Expand All @@ -6,15 +7,29 @@

rj = None
port = 6379

REDIS_CLUSTER_HOST = os.getenv("REDIS_HOST")
REDIS_CLUSTER_PORT = os.getenv("REDIS_PORT")

class ReJSONTestCase(TestCase):

def _create_client(self, *args, **kwargs):
if REDIS_CLUSTER_HOST is None or \
REDIS_CLUSTER_PORT is None:
return Client(*args, **kwargs)
else:
from rediscluster import RedisCluster
startup_nodes = [{"host": REDIS_CLUSTER_HOST,
"port": REDIS_CLUSTER_PORT}]
conn = RedisCluster(startup_nodes=startup_nodes, decode_responses=True)
return Client(client=conn, *args, **kwargs)


def setUp(self):
global rj
rj = Client(port=port, decode_responses=True)
rj = self._create_client(port=port, decode_responses=True)
rj.flushdb()


def testJSONSetGetDelShouldSucceed(self):
"Test basic JSONSet/Get/Del"

Expand Down Expand Up @@ -197,7 +212,7 @@ def decode(self, obj):
return CustomClass(k=s[1], v=s[2])
return d

rj = Client(encoder=TestEncoder(), decoder=TestDecoder(),
rj = self._create_client(encoder=TestEncoder(), decoder=TestDecoder(),
port=port, decode_responses=True)
rj.flushdb()

Expand All @@ -219,7 +234,7 @@ def testUsageExampleShouldSucceed(self):
"Test the usage example"

# Create a new rejson-py client
rj = Client(host='localhost', port=port, decode_responses=True)
rj = self._create_client(host='localhost', port=port, decode_responses=True)

# Set the key `obj` to some object
obj = {
Expand Down