Mercurial > rinkhals
diff gamelib/serializer.py @ 415:8f012ef1f64f
Start of ability to serialize game state.
author | Simon Cross <hodgestar@gmail.com> |
---|---|
date | Sat, 21 Nov 2009 12:55:08 +0000 |
parents | |
children | cf4b020e6385 |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/gamelib/serializer.py Sat Nov 21 12:55:08 2009 +0000 @@ -0,0 +1,107 @@ +""" +Interface for converting objects to and from simple structures: lists, dicts, +strings, integers and combinations there of. Used for sending objects over +the communications API. +""" + +REGISTERED_CLASSES = {} + +def simplify(item): + """Convert an item to a simple data structure.""" + if issubclass(type(item), Simplifiable): + return item.simplify() + elif type(item) is list: + return { 'list': [simplify(x) for x in item] } + elif type(item) is tuple: + return { 'tuple': tuple([simplify(x) for x in item]) } + elif item is None: + return { 'none': '' } + else: + return { 'raw': item } + +def unsimplify(value): + """Reverse the simplify process.""" + if value.has_key('class'): + cls = REGISTERED_CLASSES[value['class']] + return cls.unsimplify(value) + elif value.has_key('list'): + return [unsimplify(x) for x in value['list']] + elif value.has_key('tuple'): + return tuple([unsimplify(x) for x in value['tuple']]) + elif value.has_key('none'): + return None + elif value.has_key('raw'): + return value['raw'] + else: + raise SimplifyError("Unknown tar type key.") + +class SimplifyError(Exception): + pass + +class SimplifiableMetaclass(type): + def __init__(cls, name, bases, dct): + super(SimplifiableMetaclass, cls).__init__(name, bases, dct) + REGISTERED_CLASSES[cls.__name__] = cls + +class Simplifiable(object): + """ + Object which can be simplified() and unsimplified() (i.e. + converted to a data type which, for example, Python's XMLRPC + or json module is capable of handling). Each subclass + must provide SIMPLIFY (a list of strings giving the names + of attributes which should be stored) unless a parent class + provides the right thing. + """ + __metaclass__ = SimplifiableMetaclass + + # List of attributes which need to be stored and restored + SIMPLIFY = [] + + def make(cls): + """ + Create an object of this class without any attributes set. + """ + return cls.__new__(cls) + make = classmethod(make) + + def unsimplify(cls, value): + """ + Create an object of this class (or a sub-class) from its + simplification. + """ + actual_cls = REGISTERED_CLASSES[value['class']] + attrs = value['attributes'] + + if not issubclass(actual_cls, cls): + raise SimplifyError("Real class not a subclass of this class") + + if not len(attrs) == len(actual_cls.SIMPLIFY): + raise SimplifyError("Wrong number of attributes for this class") + + obj = actual_cls.make() + for attr, value in zip(actual_cls.SIMPLIFY, attrs): + setattr(obj, attr, unsimplify(value)) + + return obj + unsimplify = classmethod(unsimplify) + + def simplify(self): + """ + Create a simplified version (tar) of the object. + """ + value = {} + value['class'] = self.__class__.__name__ + + attrs = [] + for attr in self.SIMPLIFY: + o = getattr(self, attr) + attrs.append(simplify(o)) + + value['attributes'] = attrs + return value + + def copy(self): + """ + Return a copy of the object. + """ + return self.__class__.unsimplify(self.simplify())