From 397afa20841dd7e3e22f1b42385dda6998df183d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tom=C3=A1=C5=A1=20Kukr=C3=A1l?= Date: Thu, 12 Oct 2017 21:47:26 +0200 Subject: [PATCH] fix for entangling There was a problem with class heredity and attributes was shared in Class instead of instances. I'm changing intialization sequence to mitigate this. see https://en.wikipedia.org/wiki/Entangled_(Red_Dwarf) --- kqueen/storages/etcd.py | 36 +++++++++++++++------------- kqueen/storages/test_model_fields.py | 21 +++++++++------- 2 files changed, 33 insertions(+), 24 deletions(-) diff --git a/kqueen/storages/etcd.py b/kqueen/storages/etcd.py index 6b340ca2..4cdbb9ca 100644 --- a/kqueen/storages/etcd.py +++ b/kqueen/storages/etcd.py @@ -28,7 +28,9 @@ def __init__(self, *args, **kwargs): """ - self.value = None + # TODO: pass value via args[0] + + self.value = kwargs.get('value', None) self.required = kwargs.get('required', False) # waiting for @profesor to bring bright new idea @@ -100,13 +102,14 @@ def serialize(self): class ModelMeta(type): def __new__(cls, clsname, superclasses, attributedict): newattributes = attributedict.copy() + fields = {} # loop attributes and set getters and setter for Fields for attr_name, attr in attributedict.items(): attr_class = attr.__class__ if hasattr(attr_class, 'is_field') and attr_class.is_field: name_hidden = '_{}'.format(attr_name) - newattributes[name_hidden] = attr + fields[attr_name] = attr def fget(self, k=attr_name): att = getattr(self, "_{}".format(k)) @@ -119,6 +122,8 @@ def fset(self, value, k=attr_name): newattributes[attr_name] = property(fget, fset) logger.debug('Setting {} to point to {}'.format(attr_name, name_hidden)) + newattributes['_fields'] = fields + return type.__new__(cls, clsname, superclasses, newattributes) @@ -133,11 +138,12 @@ def __init__(self, *arfg, **kwargs): self._db = db # loop fields and set it - for a in self.__class__.get_field_names(): - field_class = getattr(self, '_{}'.format(a)).__class__ - if hasattr(field_class, 'is_field') and kwargs.get(a): - setattr(self, a, kwargs.get(a)) - logger.debug('Setting {} to {}'.format(a, kwargs.get(a))) + for field_name, field in self.__class__.get_fields().items(): + field_class = field.__class__ + if hasattr(field_class, 'is_field'): + field_object = field_class(**field.__dict__) + field_object.set_value(kwargs.get(field_name)) + setattr(self, '_{}'.format(field_name), field_object) @classmethod def get_model_name(cls): @@ -230,19 +236,17 @@ def deserialize(cls, serialized, **kwargs): return o + @classmethod + def get_fields(cls): + """Return dict of fields and it classes""" + + return cls._fields + @classmethod def get_field_names(cls): """Return list of field names""" - fields = [] - - for a in cls.__dict__.keys(): - field = getattr(cls, a).__class__ - if hasattr(field, 'is_field'): - if a.startswith('_'): - a = a[1:] - fields.append(a) - return fields + return list(cls._fields.keys()) def get_db_key(self): if not self.id: diff --git a/kqueen/storages/test_model_fields.py b/kqueen/storages/test_model_fields.py index ff9b396b..06ad700d 100644 --- a/kqueen/storages/test_model_fields.py +++ b/kqueen/storages/test_model_fields.py @@ -57,6 +57,7 @@ def test_required(self, required): class TestModelInit: def setup(self): self.model = create_model() + self.obj = self.model(**model_kwargs) @pytest.mark.parametrize('field_name,field_value', model_kwargs.items()) def test_init_string(self, field_name, field_value): @@ -72,7 +73,7 @@ def test_init_string(self, field_name, field_value): def test_field_property_getters(self, attr, group): attr_name = '{}{}'.format(group, attr) - assert hasattr(self.model, attr_name) + assert hasattr(self.obj, attr_name) class TestGetFieldNames: @@ -137,19 +138,23 @@ def test_deserialization(self, create_object): class TestDuplicateId: - def test_write(self): - model = create_model() + def setup(self): + self.model = create_model() + + self.obj1_kwargs = {'string': 'object 1', 'json': {'a': 1, 'b': 2, 'c': 'tri'}, 'secret': 'pass'} + self.obj2_kwargs = {'string': 'object 2', 'json': {'a': 1, 'b': 2, 'c': 'tri'}, 'secret': 'pass'} - obj1_kwargs = {'string': 'object 1', 'json': {'a': 1, 'b': 2, 'c': 'tri'}, 'secret': 'pass'} - obj2_kwargs = {'string': 'object2', 'json': {'a': 1, 'b': 2, 'c': 'tri'}, 'secret': 'pass'} + def test_with_save(self): + """"Save object are not same""" + obj1 = self.model(**self.obj1_kwargs) + obj2 = self.model(**self.obj2_kwargs) + + assert obj1 != obj2 - obj1 = model(**obj1_kwargs) obj1.save() - obj2 = model(**obj2_kwargs) obj2.save() print(obj1.get_dict()) print(obj2.get_dict()) - assert obj1 != obj2 assert obj1.id != obj2.id