Using TokyoTyrant as a Model-like TokyoTyrantStorage

Python
2011-06-09 17:37 (13 years ago) ytyng
# -*- coding: utf-8 -*-

"""
Using TokyoTyrant as a Model

class Soldier(TokyoTyrantStorage):
    
    hp = TokyoTyrantStorage.Field(default=0)
    mp = TokyoTyrantStorage.Field(default=0)

cain = Soldier('Cain')
cain.hp = 100
cain.mp = 50
cain.save()

abel = Soldier('Abel')
abel.hp = 50
abel.mp = 100
abel.save()

cain = Soldier('Cain')
cain.hp -= 80
cain.save()

abel = Soldier('Abel')
abel.mp -= 20
abel.save()

cain = Soldier('Cain')
cain.hp = min(cain.hp + 50, 100)
cain.save()

cain = Soldier('Cain')
cain.hp

Out: 70

"""

import logging
from tokyotyrant import get_client
import msgpack

class TokyoTyrantStorage(object):
    """
    Base class for using TokyoTyrant as a dictionary
    Please use it by inheritance
    """
    packer = msgpack.Packer()
    tt_client = get_client()

    def __new__(cls, *args, **kwargs):
        for k, v in vars(cls).items():
            if isinstance(v, TokyoTyrantStorage.Field):
                v.set_field_name(k)
        return object.__new__(cls)

    def __init__(self, key_object):
        """
        @param key_object: Django model instance, etc. player or osuser
        Override and if you don't want to call super's __init__,
        just call self.after_init(key_part)
        """
        self.key_object = key_object
        key_part = getattr(key_object, 'pk', str(key_object))
        self.after_init(key_part)

    def after_init(self, key_part):
        """
        Second half of initialization process
        @param (str)key_part: Unique string used as the base for key generation
        """
        self.kvs_key = '%s::%s' % (self.__class__.__name__, key_part)
        bulk_storage = self.tt_client.get(self.kvs_key, None)
        if bulk_storage:
            self.storage = msgpack.unpackb(bulk_storage)
        else:
            self.storage = {}

    def get(self, k, default=None):
        return self.storage.get(k,default)

    def set(self, k, value):
        self.storage[k] = value

    def save(self):
        """
        Save storage
        """
        self.tt_client.set(self.kvs_key, self.packer.pack(self.storage))

    def delete(self):
        """
        Delete storage
        """
        self.tt_client.out(self.kvs_key)
        self.storage = {}

    def dump(self):
        logging.debug("[TokyoTyrantStorage] dump: kvs_key=%s, storage=%r" % (self.kvs_key, self.storage))


    class Field(object):
        """
        Field that can be used in TokyoTyrantStorage
        Use it like score = TokyoTyrantStorage.Field(default=0).
        """

        def __init__(self, key_name=None, default=None):
            self._key_name = key_name 
            self.default = default

        def __get__(self, inst, type=None):
            assert isinstance(inst, TokyoTyrantStorage), '%s use only TokyoTyrantStorage class.' % self.__class__.__name__
            return inst.get(self.key_name, self.default)

        def __set__(self, inst, value):
            assert isinstance(inst, TokyoTyrantStorage), '%s use only TokyoTyrantStorage class.' % self.__class__.__name__
            inst.set(self.key_name, value)

        def set_field_name(self, field_name):
            # Called from TokyoTyrantStorage.__new__
            self.field_name = field_name

        @property
        def key_name(self):
            return self._key_name or self.field_name
Currently unrated
The author runs the application development company Cyberneura.
We look forward to discussing your development needs.

Archive

2025
2024
2023
2022
2021
2020
2019
2018
2017
2016
2015
2014
2013
2012
2011