/redis-bindings

Redis native types in Python.

Primary LanguagePythonMIT LicenseMIT

redis-bindings

https://travis-ci.org/vladimirshkoda/redis-bindings.svg?branch=master

Redis bindings is an attempt to bring Redis types into Python as native ones. It is based on redis-py and has the following types implemented so far:

Moreover, it provides some abstract classes as Redis descriptors:

  • IRedisField
  • IRedisListField
  • IRedisDictField

The classes are abstract because it requires user to override get_key_name method to define key name for Redis. Here is an example of how it can be implemented (can be found in example.py).

"""An example of the Redis descriptors usage."""

from redis import Redis
from redistypes import IRedisField, IRedisListField

r_connection = Redis()


class RedisField(IRedisField):
    """IRedisField implementation."""

    def __init__(self, pickling=True):
        """Set ``r_connection`` as the Redis connection pool by default."""
        super().__init__(
            redis_connection=r_connection,
            pickling=pickling,
        )

    def get_key_name(self, instance):
        """
        Return Redis key name of the attribute.

        It enforces instance using this descriptor to have the ``pk`` attribute.
        """
        return ':'.join([
            instance.__class__.__name__, str(instance.pk), self.name,
        ])


class RedisListField(RedisField, IRedisListField):
    """IRedisListField implementation."""


class Student(object):
    """Casual model of student."""

    name = RedisField()
    subjects = RedisListField()

    def __init__(self, pk, name=None, subjects=None):
        """Student instance has to be initialized with a primary key ``pk``."""
        self.pk = pk
        if name:
            self.name = name
        if subjects:
            self.subjects = subjects

The defined above Student model has the following behaviour:

>>> from example import Student
>>> student = Student(pk=1, name='John Galt', subjects=['math', 'physics'])
>>> student.name
John Galt
>>> student.subjects
RedisList: ['math', 'physics']
>>> student.subjects.append('p.e.')
>>> student.subjects
RedisList: ['math', 'physics', 'p.e.']
>>> student.subjects[-1] = 'art'
>>> student.subjects
RedisList: ['math', 'physics', 'art']

Let's check what keys we've got in Redis:

>>> from redis import Redis
>>> r = Redis()
>>> r.keys()
[b'Student:1:name', b'Student:1:subjects']

Warning!

As you saw above, we are able to change items of the RedisList, e.g. replace one subject with another by index. But what if we set list value to the regular field? Let's replace name of the student with list consisting of the first name and the last name.

>>> student.name = ['John', 'Galt']
>>> student.name
['John', 'Galt']
>>> student.name[-1] = 'Smith'
>>> student.name
['John', 'Galt']

In that way, we changed the name value from string to list of two items, but since name is a simple RedisField keeping all value as string in Redis, we are not able to modify stored items themselves. All values stored inside the Redis data structures are immutable! As the example above shows, index lookup from the list stored as string in redis will return a copy of the item.