Skip to content

Commit 12a15ee

Browse files
authored
Merge pull request #6 from hootnot/test-suite
Test suite
2 parents 473567a + e311d1e commit 12a15ee

File tree

9 files changed

+278
-213
lines changed

9 files changed

+278
-213
lines changed

.travis.yml

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,10 @@
11
language: python
22
python:
33
- 2.7
4+
- 3.3
5+
- 3.4
46
- 3.5
5-
6-
matrix:
7-
allow_failures:
8-
- python: 3.5
7+
- 3.6
98

109
install:
1110
# Get Redis
@@ -14,13 +13,14 @@ install:
1413
- git clone --depth=1 https://github.com/RedisLabsModules/ReJSON.git && cd ReJSON && make && cd ..
1514
# Install requirements
1615
- pip install -r requirements.txt
16+
- pip install coveralls
17+
- pip install wheel
18+
- pip install twine
1719
# Install rejson-py to test rejson-py
18-
- pip install -e .
20+
# - pip install -e .
1921

2022
before_script:
2123
- ./redis/src/redis-server --loadmodule ReJSON/src/rejson.so &
2224

2325
script:
24-
- cd test
25-
- python -munittest discover
26-
26+
- coverage run --source=rejson setup.py test

README.md

Lines changed: 0 additions & 134 deletions
This file was deleted.

README.rst

Lines changed: 158 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,158 @@
1+
ReJSON Python Client
2+
====================
3+
4+
.. image:: https://travis-ci.org/RedisLabs/rejson-py.svg?branch=master
5+
:target: https://travis-ci.org/RedisLabs/rejson-py
6+
7+
.. image:: https://img.shields.io/pypi/pyversions/rejson.svg
8+
:target: https://github.com/RedisLabs/rejson-py
9+
10+
rejson-py is a package that allows storing, updating and querying objects as
11+
JSON documents in a `Redis`_ database that is extended with the
12+
`ReJSON module`_. The package extends
13+
`redis-py`_'s interface with ReJSON's
14+
API, and performs on-the-fly serialization/deserialization of objects to/from
15+
JSON.
16+
17+
.. _`Redis`: https://redis.io
18+
.. _`ReJSON module`: https://github.com/redislabsmodules/rejson
19+
.. _`redis-py`: https://github.com/andymccurdy/redis-py
20+
21+
Installation
22+
------------
23+
24+
.. code-block:: bash
25+
26+
$ pip install rejson
27+
28+
Usage example
29+
-------------
30+
31+
.. code-block:: python
32+
33+
from rejson import Client, Path
34+
35+
rj = Client(host='localhost', port=6379)
36+
37+
# Set the key `obj` to some object
38+
obj = {
39+
'answer': 42,
40+
'arr': [None, True, 3.14],
41+
'truth': {
42+
'coord': 'out there'
43+
}
44+
}
45+
rj.jsonset('obj', Path.rootPath(), obj)
46+
47+
# Get something
48+
print 'Is there anybody... {}?'.format(
49+
rj.jsonget('obj', Path('.truth.coord'))
50+
)
51+
52+
# Delete something (or perhaps nothing), append something and pop it
53+
rj.jsondel('obj', Path('.arr[0]'))
54+
rj.jsonarrappend('obj', Path('.arr'), 'something')
55+
print '{} popped!'.format(rj.jsonarrpop('obj', Path('.arr')))
56+
57+
# Update something else
58+
rj.jsonset('obj', Path('.answer'), 2.17)
59+
60+
# And use just like the regular redis-py client
61+
jp = rj.pipeline()
62+
jp.set('foo', 'bar')
63+
jp.jsonset('baz', Path.rootPath(), 'qaz')
64+
jp.execute()
65+
66+
67+
Encoding/Decoding
68+
-----------------
69+
70+
rejson-py uses Python's json_.
71+
The client can be set to use custom encoders/decoders at creation, or by calling
72+
explicitly the setEncoder_ () and
73+
setDecoder_ () methods, respectively.
74+
75+
.. _json: https://docs.python.org/2/library/json.html
76+
.. _setDecoder: ./API.md#setdecoder
77+
.. _setEncoder: ./API.md#setencoder
78+
79+
The following shows how to use this for a custom class that's stored as
80+
a JSON string for example:
81+
82+
.. code-block:: python
83+
84+
from json import JSONEncoder, JSONDecoder
85+
from rejson import Client
86+
87+
class CustomClass(object):
88+
"Some non-JSON-serializable"
89+
def __init__(self, s=None):
90+
if s is not None:
91+
# deserialize the instance from the serialization
92+
if s.startswith('CustomClass:'):
93+
...
94+
else:
95+
raise Exception('unknown format')
96+
else:
97+
# initialize the instance
98+
...
99+
100+
def __str__(self):
101+
_str = 'CustomClass:'
102+
# append the instance's state to the serialization
103+
...
104+
return _str
105+
106+
...
107+
108+
class CustomEncoder(JSONEncoder):
109+
"A custom encoder for the custom class"
110+
def default(self, obj):
111+
if isinstance(obj, CustomClass):
112+
return str(obj)
113+
return json.JSONEncoder.encode(self, obj)
114+
115+
class TestDecoder(JSONDecoder):
116+
"A custom decoder for the custom class"
117+
def decode(self, obj):
118+
d = json.JSONDecoder.decode(self, obj)
119+
if isinstance(d, basestring) and d.startswith('CustomClass:'):
120+
return CustomClass(d)
121+
return d
122+
123+
# Create a new instance of CustomClass
124+
obj = CustomClass()
125+
126+
# Create a new client with the custom encoder and decoder
127+
rj = Client(encoder=CustomEncoder(), decoder=CustomDecoder())
128+
129+
# Store the object
130+
rj.jsonset('custom', Path.rootPath(), obj))
131+
132+
# Retrieve it
133+
obj = rj.jsonget('custom', Path.rootPath())
134+
135+
136+
API
137+
---
138+
139+
As rejson-py exposes the same methods as redis-py, it can be used as a drop-in
140+
replacement. On top of Redis' core commands, the client also adds ReJSON's
141+
vocabulary and a couple of helper methods. These are documented in the
142+
[API.md](API.md) file, which can be generated by running:
143+
144+
.. code-block:: bash
145+
146+
$ python gendoc rejson > API.md
147+
148+
149+
For complete documentation about ReJSON's commands, refer to rejson_.
150+
151+
.. _`rejson`: http://rejson.io
152+
153+
License
154+
-------
155+
156+
`BSD 2-Clause`_
157+
158+
.. _`BSD 2-Clause`: https://github.com/RedisLabs/rejson-py/blob/master/LICENSE

rejson/__init__.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -112,6 +112,6 @@ def decode(self, obj):
112112
obj = rj.jsonget('custom', Path.rootPath())
113113
```
114114
"""
115-
115+
__version__ = "0.1.0"
116116
from .client import Client
117117
from .path import Path

rejson/client.py

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
1-
from sys import stdout
1+
import six
22
import json
3-
from redis import StrictRedis, exceptions
3+
from redis import StrictRedis
44
from redis.client import BasePipeline
55
from redis._compat import (long, nativestr)
66
from .path import Path
@@ -14,7 +14,7 @@ def str_path(p):
1414

1515
def float_or_long(n):
1616
"Return a number from a Redis reply"
17-
if isinstance(n, str):
17+
if isinstance(n, six.string_types):
1818
return float(n)
1919
else:
2020
return long(n)
@@ -90,7 +90,7 @@ def __init__(self, encoder=None, decoder=None, *args, **kwargs):
9090
'JSON.ARRTRIM': long_or_none,
9191
'JSON.OBJLEN': long_or_none,
9292
}
93-
for k, v in MODULE_CALLBACKS.iteritems():
93+
for k, v in six.iteritems(MODULE_CALLBACKS):
9494
self.set_response_callback(k, v)
9595

9696
def setEncoder(self, encoder):

requirements.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,3 @@
11
hiredis==0.2.0
22
redis==2.10.5
3+
six>=1.10

0 commit comments

Comments
 (0)