Skip to content

Test suite #6

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 19 commits into from
Jun 5, 2017
Merged
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
16 changes: 8 additions & 8 deletions .travis.yml
Original file line number Diff line number Diff line change
@@ -1,11 +1,10 @@
language: python
python:
- 2.7
- 3.3
- 3.4
- 3.5

matrix:
allow_failures:
- python: 3.5
- 3.6

install:
# Get Redis
Expand All @@ -14,13 +13,14 @@ install:
- git clone --depth=1 https://github.com/RedisLabsModules/ReJSON.git && cd ReJSON && make && cd ..
# Install requirements
- pip install -r requirements.txt
- pip install coveralls
- pip install wheel
- pip install twine
# Install rejson-py to test rejson-py
- pip install -e .
# - pip install -e .

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

script:
- cd test
- python -munittest discover

- coverage run --source=rejson setup.py test
134 changes: 0 additions & 134 deletions README.md

This file was deleted.

158 changes: 158 additions & 0 deletions README.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,158 @@
ReJSON Python Client
====================

.. image:: https://travis-ci.org/RedisLabs/rejson-py.svg?branch=master
:target: https://travis-ci.org/RedisLabs/rejson-py

.. image:: https://img.shields.io/pypi/pyversions/rejson.svg
:target: https://github.com/RedisLabs/rejson-py

rejson-py is a package that allows storing, updating and querying objects as
JSON documents in a `Redis`_ database that is extended with the
`ReJSON module`_. The package extends
`redis-py`_'s interface with ReJSON's
API, and performs on-the-fly serialization/deserialization of objects to/from
JSON.

.. _`Redis`: https://redis.io
.. _`ReJSON module`: https://github.com/redislabsmodules/rejson
.. _`redis-py`: https://github.com/andymccurdy/redis-py

Installation
------------

.. code-block:: bash

$ pip install rejson

Usage example
-------------

.. code-block:: python

from rejson import Client, Path

rj = Client(host='localhost', port=6379)

# Set the key `obj` to some object
obj = {
'answer': 42,
'arr': [None, True, 3.14],
'truth': {
'coord': 'out there'
}
}
rj.jsonset('obj', Path.rootPath(), obj)

# Get something
print 'Is there anybody... {}?'.format(
rj.jsonget('obj', Path('.truth.coord'))
)

# Delete something (or perhaps nothing), append something and pop it
rj.jsondel('obj', Path('.arr[0]'))
rj.jsonarrappend('obj', Path('.arr'), 'something')
print '{} popped!'.format(rj.jsonarrpop('obj', Path('.arr')))

# Update something else
rj.jsonset('obj', Path('.answer'), 2.17)

# And use just like the regular redis-py client
jp = rj.pipeline()
jp.set('foo', 'bar')
jp.jsonset('baz', Path.rootPath(), 'qaz')
jp.execute()


Encoding/Decoding
-----------------

rejson-py uses Python's json_.
The client can be set to use custom encoders/decoders at creation, or by calling
explicitly the setEncoder_ () and
setDecoder_ () methods, respectively.

.. _json: https://docs.python.org/2/library/json.html
.. _setDecoder: ./API.md#setdecoder
.. _setEncoder: ./API.md#setencoder

The following shows how to use this for a custom class that's stored as
a JSON string for example:

.. code-block:: python

from json import JSONEncoder, JSONDecoder
from rejson import Client

class CustomClass(object):
"Some non-JSON-serializable"
def __init__(self, s=None):
if s is not None:
# deserialize the instance from the serialization
if s.startswith('CustomClass:'):
...
else:
raise Exception('unknown format')
else:
# initialize the instance
...

def __str__(self):
_str = 'CustomClass:'
# append the instance's state to the serialization
...
return _str

...

class CustomEncoder(JSONEncoder):
"A custom encoder for the custom class"
def default(self, obj):
if isinstance(obj, CustomClass):
return str(obj)
return json.JSONEncoder.encode(self, obj)

class TestDecoder(JSONDecoder):
"A custom decoder for the custom class"
def decode(self, obj):
d = json.JSONDecoder.decode(self, obj)
if isinstance(d, basestring) and d.startswith('CustomClass:'):
return CustomClass(d)
return d

# Create a new instance of CustomClass
obj = CustomClass()

# Create a new client with the custom encoder and decoder
rj = Client(encoder=CustomEncoder(), decoder=CustomDecoder())

# Store the object
rj.jsonset('custom', Path.rootPath(), obj))

# Retrieve it
obj = rj.jsonget('custom', Path.rootPath())


API
---

As rejson-py exposes the same methods as redis-py, it can be used as a drop-in
replacement. On top of Redis' core commands, the client also adds ReJSON's
vocabulary and a couple of helper methods. These are documented in the
[API.md](API.md) file, which can be generated by running:

.. code-block:: bash

$ python gendoc rejson > API.md


For complete documentation about ReJSON's commands, refer to rejson_.

.. _`rejson`: http://rejson.io

License
-------

`BSD 2-Clause`_

.. _`BSD 2-Clause`: https://github.com/RedisLabs/rejson-py/blob/master/LICENSE
2 changes: 1 addition & 1 deletion rejson/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -112,6 +112,6 @@ def decode(self, obj):
obj = rj.jsonget('custom', Path.rootPath())
```
"""

__version__ = "0.1.0"
from .client import Client
from .path import Path
8 changes: 4 additions & 4 deletions rejson/client.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
from sys import stdout
import six
import json
from redis import StrictRedis, exceptions
from redis import StrictRedis
from redis.client import BasePipeline
from redis._compat import (long, nativestr)
from .path import Path
Expand All @@ -14,7 +14,7 @@ def str_path(p):

def float_or_long(n):
"Return a number from a Redis reply"
if isinstance(n, str):
if isinstance(n, six.string_types):
return float(n)
else:
return long(n)
Expand Down Expand Up @@ -90,7 +90,7 @@ def __init__(self, encoder=None, decoder=None, *args, **kwargs):
'JSON.ARRTRIM': long_or_none,
'JSON.OBJLEN': long_or_none,
}
for k, v in MODULE_CALLBACKS.iteritems():
for k, v in six.iteritems(MODULE_CALLBACKS):
self.set_response_callback(k, v)

def setEncoder(self, encoder):
Expand Down
1 change: 1 addition & 0 deletions requirements.txt
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
hiredis==0.2.0
redis==2.10.5
six>=1.10
Loading