Skip to content

Commit

Permalink
dirty
Browse files Browse the repository at this point in the history
  • Loading branch information
pipermerriam committed Apr 12, 2018
1 parent 7ee1abf commit 7ef3ef3
Show file tree
Hide file tree
Showing 2 changed files with 404 additions and 0 deletions.
115 changes: 115 additions & 0 deletions rlp/sedes/serializable.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,115 @@
import abc
import collections

from rlp.exceptions import (
ListSerializationError,
ObjectSerializationError,
ListDeserializationError,
ObjectDeserializationError,
)

from .lists import (
List,
)


class FieldsMeta:
fields = None

@classmethod
def get_field_names(cls):
if cls.fields:
names, _ = zip(*cls.fields)
else:
names = tuple()
return names

@classmethod
def get_sedes(cls):
if cls.fields:
_, sedes = zip(*cls.fields)
else:
sedes = tuple()
return List(sedes)


class SerializableMeta(abc.ABCMeta):
def __new__(cls, name, bases, attrs):
fields = attrs.pop('fields', tuple())

fields_meta = type('FieldsMeta', (FieldsMeta,), {'fields': fields})
attrs['_meta'] = fields_meta
return super(SerializableMeta, cls).__new__(cls, name, bases, attrs)


class Serializable(collections.Sequence, metaclass=SerializableMeta):
def __init__(self, *args, **kwargs):

# check keyword arguments are known
field_set = set(self._meta.get_field_names())

# set positional arguments
for field, arg in zip(self._meta.get_field_names(), args):
setattr(self, field, arg)
field_set.remove(field)

# set keyword arguments, if not already set
for field, value in kwargs.items():
if field in field_set:
setattr(self, field, value)
field_set.remove(field)
else:
raise AttributeError("Attempt to set unknown field: {0}".format(field))

if len(field_set) != 0:
raise TypeError('Not all fields initialized. Missing: %r' % field_set)

def __iter__(self):
for field in self._meta.get_field_names():
yield getattr(self, field)

def __getitem__(self, idx):
if isinstance(idx, int):
field = self._meta.get_field_names()[idx]
return getattr(self, field)
else:
raise NotImplementedError("not implemented")

def __len__(self):
return len(self._meta.fields)

@classmethod
def get_sedes(cls):
return cls._meta.get_sedes()

@classmethod
def serialize(cls, obj):
try:
result = cls.get_sedes().serialize(obj)
except ListSerializationError as e:
raise ObjectSerializationError(obj=obj, sedes=cls, list_exception=e)
else:
return result

@classmethod
def deserialize(cls, serial, exclude=None, mutable=False, **kwargs):
try:
values = cls.get_sedes().deserialize(serial)
except ListDeserializationError as e:
raise ObjectDeserializationError(serial=serial, sedes=cls, list_exception=e)

params = {
field: value
for field, value
in zip(cls._meta.get_field_names(), values)
if exclude is None or field not in exclude
}
obj = cls(**dict(list(params.items()) + list(kwargs.items())))

# TODO: mutability
return obj

@classmethod
def exclude(cls, excluded_fields):
"""Create a new sedes considering only a reduced set of fields."""
raise NotImplementedError("Not yet implemented")
Loading

0 comments on commit 7ef3ef3

Please sign in to comment.