Skip to content

Commit 3bcc9a0

Browse files
committed
More documentation, mainly encoder
1 parent 55b5d05 commit 3bcc9a0

File tree

6 files changed

+219
-12
lines changed

6 files changed

+219
-12
lines changed

API.md

+73-6
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,69 @@ jp.jsonset('baz', Path.rootPath(), 'qaz')
5151
jp.execute()
5252
```
5353

54+
## Encoding/Decoding
55+
56+
rejson-py uses Python's [`json`](https://docs.python.org/2/library/json.html).
57+
The client can be set to use custom encoders/decoders at creation, or by calling
58+
explicitly the [`setEncoder()`](API.md#setencoder) and
59+
[`setDecoder()`](API.md#setdecoder) methods, respectively.
60+
61+
The following shows how to use this for a custom class that's stored as
62+
a JSON string for example:
63+
64+
```python
65+
from json import JSONEncoder, JSONDecoder
66+
from rejson import Client
67+
68+
class CustomClass(object):
69+
"Some non-JSON-serializable"
70+
def __init__(self, s=None):
71+
if s is not None:
72+
# deserialize the instance from the serialization
73+
if s.startswith('CustomClass:'):
74+
...
75+
else:
76+
raise Exception('unknown format')
77+
else:
78+
# initialize the instance
79+
...
80+
81+
def __str__(self):
82+
_str = 'CustomClass:'
83+
# append the instance's state to the serialization
84+
...
85+
return _str
86+
87+
...
88+
89+
class CustomEncoder(JSONEncoder):
90+
"A custom encoder for the custom class"
91+
def default(self, obj):
92+
if isinstance(obj, CustomClass):
93+
return str(obj)
94+
return json.JSONEncoder.encode(self, obj)
95+
96+
class TestDecoder(JSONDecoder):
97+
"A custom decoder for the custom class"
98+
def decode(self, obj):
99+
d = json.JSONDecoder.decode(self, obj)
100+
if isinstance(d, basestring) and d.startswith('CustomClass:'):
101+
return CustomClass(d)
102+
return d
103+
104+
# Create a new instance of CustomClass
105+
obj = CustomClass()
106+
107+
# Create a new client with the custom encoder and decoder
108+
rj = Client(encoder=CustomEncoder(), decoder=CustomDecoder())
109+
110+
# Store the object
111+
rj.jsonset('custom', Path.rootPath(), obj))
112+
113+
# Retrieve it
114+
obj = rj.jsonget('custom', Path.rootPath())
115+
```
116+
54117
## Class Client
55118
This class subclasses redis-py's `StrictRedis` and implements ReJSON's
56119
commmands (prefixed with "json").
@@ -68,9 +131,8 @@ def __init__(self, encoder=None, decoder=None, *args, **kwargs)
68131

69132
Creates a new ReJSON client.
70133

71-
72-
``encoder`` is an instance of a ``json.JSONEncoder`` class.
73-
``decoder`` is an instance of a ``json.JSONDecoder`` class.
134+
``encoder`` should be an instance of a ``json.JSONEncoder`` class
135+
``decoder`` should be an instance of a ``json.JSONDecoder`` class
74136

75137

76138
### jsonarrappend
@@ -303,7 +365,8 @@ def setDecoder(self, decoder)
303365

304366

305367

306-
Sets the decoder
368+
Sets the client's decoder
369+
``decoder`` should be an instance of a ``json.JSONDecoder`` class
307370

308371

309372
### setEncoder
@@ -315,13 +378,14 @@ def setEncoder(self, encoder)
315378

316379

317380

318-
Sets the encoder
381+
Sets the client's encoder
382+
``encoder`` should be an instance of a ``json.JSONEncoder`` class
319383

320384

321385

322386

323387
## Class Path
324-
None
388+
This class represents a path in a JSON value
325389
### \_\_init\_\_
326390
```py
327391

@@ -331,5 +395,8 @@ def __init__(self, path)
331395

332396

333397

398+
Make a new path based on the string representation in `path`
399+
400+
334401

335402

README.md

+63
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,69 @@ jp.jsonset('baz', Path.rootPath(), 'qaz')
5050
jp.execute()
5151
```
5252

53+
## Encoding/Decoding
54+
55+
rejson-py uses Python's [`json`](https://docs.python.org/2/library/json.html).
56+
The client can be set to use custom encoders/decoders at creation, or by calling
57+
explicitly the [`setEncoder()`](API.md#setencoder) and
58+
[`setDecoder()`](API.md#setdecoder) methods, respectively.
59+
60+
The following shows how to use this for a custom class that's stored as
61+
a JSON string for example:
62+
63+
```python
64+
from json import JSONEncoder, JSONDecoder
65+
from rejson import Client
66+
67+
class CustomClass(object):
68+
"Some non-JSON-serializable"
69+
def __init__(self, s=None):
70+
if s is not None:
71+
# deserialize the instance from the serialization
72+
if s.startswith('CustomClass:'):
73+
...
74+
else:
75+
raise Exception('unknown format')
76+
else:
77+
# initialize the instance
78+
...
79+
80+
def __str__(self):
81+
_str = 'CustomClass:'
82+
# append the instance's state to the serialization
83+
...
84+
return _str
85+
86+
...
87+
88+
class CustomEncoder(JSONEncoder):
89+
"A custom encoder for the custom class"
90+
def default(self, obj):
91+
if isinstance(obj, CustomClass):
92+
return str(obj)
93+
return json.JSONEncoder.encode(self, obj)
94+
95+
class TestDecoder(JSONDecoder):
96+
"A custom decoder for the custom class"
97+
def decode(self, obj):
98+
d = json.JSONDecoder.decode(self, obj)
99+
if isinstance(d, basestring) and d.startswith('CustomClass:'):
100+
return CustomClass(d)
101+
return d
102+
103+
# Create a new instance of CustomClass
104+
obj = CustomClass()
105+
106+
# Create a new client with the custom encoder and decoder
107+
rj = Client(encoder=CustomEncoder(), decoder=CustomDecoder())
108+
109+
# Store the object
110+
rj.jsonset('custom', Path.rootPath(), obj))
111+
112+
# Retrieve it
113+
obj = rj.jsonget('custom', Path.rootPath())
114+
```
115+
53116
## API
54117

55118
As rejson-py exposes the same methods as redis-py, it can be used as a drop-in

rejson/__init__.py

+63
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,69 @@
4848
jp.jsonset('baz', Path.rootPath(), 'qaz')
4949
jp.execute()
5050
```
51+
52+
## Encoding/Decoding
53+
54+
rejson-py uses Python's [`json`](https://docs.python.org/2/library/json.html).
55+
The client can be set to use custom encoders/decoders at creation, or by calling
56+
explicitly the [`setEncoder()`](API.md#setencoder) and
57+
[`setDecoder()`](API.md#setdecoder) methods, respectively.
58+
59+
The following shows how to use this for a custom class that's stored as
60+
a JSON string for example:
61+
62+
```python
63+
from json import JSONEncoder, JSONDecoder
64+
from rejson import Client
65+
66+
class CustomClass(object):
67+
"Some non-JSON-serializable"
68+
def __init__(self, s=None):
69+
if s is not None:
70+
# deserialize the instance from the serialization
71+
if s.startswith('CustomClass:'):
72+
...
73+
else:
74+
raise Exception('unknown format')
75+
else:
76+
# initialize the instance
77+
...
78+
79+
def __str__(self):
80+
_str = 'CustomClass:'
81+
# append the instance's state to the serialization
82+
...
83+
return _str
84+
85+
...
86+
87+
class CustomEncoder(JSONEncoder):
88+
"A custom encoder for the custom class"
89+
def default(self, obj):
90+
if isinstance(obj, CustomClass):
91+
return str(obj)
92+
return json.JSONEncoder.encode(self, obj)
93+
94+
class TestDecoder(JSONDecoder):
95+
"A custom decoder for the custom class"
96+
def decode(self, obj):
97+
d = json.JSONDecoder.decode(self, obj)
98+
if isinstance(d, basestring) and d.startswith('CustomClass:'):
99+
return CustomClass(d)
100+
return d
101+
102+
# Create a new instance of CustomClass
103+
obj = CustomClass()
104+
105+
# Create a new client with the custom encoder and decoder
106+
rj = Client(encoder=CustomEncoder(), decoder=CustomDecoder())
107+
108+
# Store the object
109+
rj.jsonset('custom', Path.rootPath(), obj))
110+
111+
# Retrieve it
112+
obj = rj.jsonget('custom', Path.rootPath())
113+
```
51114
"""
52115

53116
from .client import Client

rejson/client.py

+12-5
Original file line numberDiff line numberDiff line change
@@ -65,9 +65,8 @@ def __init__(self, encoder=None, decoder=None, *args, **kwargs):
6565
"""
6666
Creates a new ReJSON client.
6767
68-
69-
``encoder`` is an instance of a ``json.JSONEncoder`` class.
70-
``decoder`` is an instance of a ``json.JSONDecoder`` class.
68+
``encoder`` should be an instance of a ``json.JSONEncoder`` class
69+
``decoder`` should be an instance of a ``json.JSONDecoder`` class
7170
"""
7271
self.setEncoder(encoder)
7372
self.setDecoder(decoder)
@@ -95,15 +94,21 @@ def __init__(self, encoder=None, decoder=None, *args, **kwargs):
9594
self.set_response_callback(k, v)
9695

9796
def setEncoder(self, encoder):
98-
"Sets the encoder"
97+
"""
98+
Sets the client's encoder
99+
``encoder`` should be an instance of a ``json.JSONEncoder`` class
100+
"""
99101
if not encoder:
100102
self._encoder = json.JSONEncoder()
101103
else:
102104
self._encoder = encoder
103105
self._encode = self._encoder.encode
104106

105107
def setDecoder(self, decoder):
106-
"Sets the decoder"
108+
"""
109+
Sets the client's decoder
110+
``decoder`` should be an instance of a ``json.JSONDecoder`` class
111+
"""
107112
if not decoder:
108113
self._decoder = json.JSONDecoder()
109114
else:
@@ -261,6 +266,8 @@ def pipeline(self, transaction=True, shard_hint=None):
261266
should be executed atomically. Apart from making a group of operations
262267
atomic, pipelines are useful for reducing the back-and-forth overhead
263268
between the client and server.
269+
270+
Overridden in order to provide the right client through the pipeline.
264271
"""
265272
p = Pipeline(
266273
connection_pool=self.connection_pool,

rejson/path.py

+7
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,16 @@
11
class Path(object):
2+
"""
3+
This class represents a path in a JSON value
4+
"""
25
strPath = ''
36

47
@staticmethod
58
def rootPath():
9+
"Returns the root path's string representation"
610
return '.'
711

812
def __init__(self, path):
13+
"""
14+
Make a new path based on the string representation in `path`
15+
"""
916
self.strPath = path

test/test.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -200,7 +200,7 @@ def decode(self, obj):
200200
self.assertEqual(CustomClass, obj.__class__)
201201
self.assertEqual('foo', obj.key)
202202
self.assertEqual('bar', obj.val)
203-
203+
204204
def testUsageExampleShouldSucceed(self):
205205
"Test the usage example"
206206

0 commit comments

Comments
 (0)