added list support
Project: http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/repo Commit: http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/commit/82d96166 Tree: http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/tree/82d96166 Diff: http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/diff/82d96166 Branch: refs/heads/ARIA-258-Convert-runtime-properties-to-attributes Commit: 82d9616661d1c6797e1d5561a5379b97b0070942 Parents: b2014b9 Author: max-orlov <ma...@gigaspaces.com> Authored: Mon May 22 15:21:53 2017 +0300 Committer: max-orlov <ma...@gigaspaces.com> Committed: Mon May 22 15:21:53 2017 +0300 ---------------------------------------------------------------------- aria/orchestrator/context/common.py | 128 ++++++++++++++++------ tests/orchestrator/context/test_operation.py | 44 ++++++-- 2 files changed, 125 insertions(+), 47 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/blob/82d96166/aria/orchestrator/context/common.py ---------------------------------------------------------------------- diff --git a/aria/orchestrator/context/common.py b/aria/orchestrator/context/common.py index d85f284..07596f6 100644 --- a/aria/orchestrator/context/common.py +++ b/aria/orchestrator/context/common.py @@ -202,7 +202,49 @@ class BaseContext(object): self.model.log._engine.dispose() -class _InstrumentedDict(dict): +class _InstrumentedCollection(object): + def _get_instrumented_collection(self, key, value): + if isinstance(value, _InstrumentedCollection): + return value + elif isinstance(value, dict): + return _InstrumentedDict(self._model, self, key, seq=value) + elif isinstance(value, list): + return _InstrumentedList(self._model, self, key, seq=value) + + return value + + def _raw_value(self, value): + if self._item_cls and isinstance(value, self._item_cls): + return value.value + return value + + def _encapsulate_value(self, key, value): + if isinstance(value, self._item_cls): + return value + # If it is not wrapped + return self._item_cls.wrap(key, value) + + def __setitem__(self, key, value): + self._set(key, value) + if self._item_cls: + # We are at the top level + field = getattr(self._parent, self._field_name) + mapi = getattr(self._model, self._item_cls.__modelname__) + + if key in field: + # Is this a existing field + value = self._set_parent(field, key, value) + else: + value = self._set_parent(field, key, self._encapsulate_value(key, value)) + + mapi.update(value) + else: + self._set(key, value) + # We are not at the top level + self._parent[self._field_name] = self + + +class _InstrumentedDict(_InstrumentedCollection, dict): def __init__(self, model, parent, field_name=None, item_cls=None, seq=None, **kwargs): self._model = model self._parent = parent @@ -223,12 +265,7 @@ class _InstrumentedDict(dict): self[key] = value def __getitem__(self, key): - value = dict.__getitem__(self, key) - if isinstance(value, _InstrumentedDict): - return value - elif isinstance(value, dict): - return _InstrumentedDict(self._model, self, key, seq=value) - return value + return self._get_instrumented_collection(key, dict.__getitem__(self, key)) def values(self): return [self[key] for key in self.keys()] @@ -240,40 +277,55 @@ class _InstrumentedDict(dict): return (key for key in self.keys()) def _set(self, key, value): - if self._item_cls and isinstance(value, self._item_cls): - value = value.value - dict.__setitem__(self, key, value) + dict.__setitem__(self, key, self._raw_value(value)) - def __setitem__(self, key, value): - self._set(key, value) - def _set_parent(value): - if key in field and isinstance(field[key], self._item_cls): - if isinstance(field[key], dict): - field[key].clear() - field[key].value = value - else: - field[key] = value - return field[key] + def _set_parent(self, field, key, value): + if key in field and isinstance(field[key], self._item_cls): + if isinstance(field[key], dict): + field[key].clear() + field[key].value = value + else: + field[key] = value + return field[key] + + +class _InstrumentedList(list, _InstrumentedCollection): + def __init__(self, model, parent, field_name=None, item_cls=None, seq=None, **kwargs): + self._model = model + self._parent = parent + self._field_name = field_name + self._item_cls = item_cls + self._load(seq, **kwargs) + + def _load(self, seq=None, **kwargs): + seq = list(item for item in seq or []) + super(_InstrumentedList, self).__init__(seq) + + def append(self, value): + self.insert(len(self), value) + def insert(self, index, value): + list.insert(self, index, self._raw_value(value)) if self._item_cls: - # We are at the top level field = getattr(self._parent, self._field_name) - mapi = getattr(self._model, self._item_cls.__modelname__) + field.insert(index, self._encapsulate_value(index, value)) + else: + self._parent[self._field_name] = self - if key in field: - # Is this a existing field - value = _set_parent(value) - else: - if not isinstance(value, self._item_cls): - # If it is not wrapped - value = self._item_cls.wrap(key, value) - value = _set_parent(value) + def __getitem__(self, key): + return self._get_instrumented_collection(key, list.__getitem__(self, key)) - mapi.update(value) + def _set(self, key, value): + list.__setitem__(self, key, value) + + def _set_parent(self, field, key, value): + if key in field and isinstance(field[key], self._item_cls): + if isinstance(field[key], list): + del field[key] + field[key].value = value else: - dict.__setitem__(self, key, value) - # We are not at the top level - self._parent[self._field_name] = self + field[key] = value + return field[key] class InstrumentCollection(object): @@ -305,6 +357,12 @@ class InstrumentCollection(object): setattr( self, self._field_name, - _InstrumentedDict(func_self.model, self._actor, field_name=self._field_name, item_cls=modeling.models.Parameter, seq=field)) + _InstrumentedDict( + func_self.model, + self._actor, + field_name=self._field_name, + item_cls=modeling.models.Parameter, + seq=field) + ) return self return _wrapper http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/blob/82d96166/tests/orchestrator/context/test_operation.py ---------------------------------------------------------------------- diff --git a/tests/orchestrator/context/test_operation.py b/tests/orchestrator/context/test_operation.py index da78199..73efff5 100644 --- a/tests/orchestrator/context/test_operation.py +++ b/tests/orchestrator/context/test_operation.py @@ -503,7 +503,7 @@ def attribute_consuming_operation(ctx, holder_path, **_): class MockActor(object): def __init__(self): self.dict_ = {} - self.attributes_list = [] + self.list_ = [] class MockModel(object): @@ -654,37 +654,57 @@ class TestList(object): @pytest.fixture def list_(self, actor, model): - return common._InstrumentedList( - actor.attributes_list, model, actor=actor, field_name='attributes_list') + return common._InstrumentedList(model, actor, field_name='list_', item_cls=Parameter) - def test_insert(self, list_): + def test_append(self, actor, list_): list_.append(Parameter.wrap('name', 'value1')) list_.append('value2') - + assert len(actor.list_) == 2 assert len(list_) == 2 - assert isinstance(list_._parent[0], Parameter) + assert isinstance(actor.list_[0], Parameter) assert list_[0] == 'value1' - assert isinstance(list_._parent[1], Parameter) + assert isinstance(actor.list_[1], Parameter) assert list_[1] == 'value2' list_[0] = 'new_value1' list_[1] = 'new_value2' - assert isinstance(list_._parent[1], Parameter) - assert isinstance(list_._parent[1], Parameter) + assert isinstance(actor.list_[1], Parameter) + assert isinstance(actor.list_[1], Parameter) assert list_[0] == 'new_value1' assert list_[1] == 'new_value2' - def test_insert_into_nested(self, list_): + def test_iter(self, list_): + list_.append('value1') + list_.append('value2') + assert sorted(list_) == sorted(['value1', 'value2']) + + def test_insert(self, actor, list_): + list_.append('value1') + list_.insert(0, 'value2') + list_.insert(2, 'value3') + list_.insert(10, 'value4') + assert sorted(list_) == sorted(['value1', 'value2', 'value3', 'value4']) + assert len(actor.list_) == 4 + + def test_set(self, list_): + list_.append('value1') + list_.append('value2') + + list_[1] = 'value3' + assert len(list_) == 2 + assert sorted(list_) == sorted(['value1', 'value3']) + + def test_insert_into_nested(self, actor, list_): list_.append([]) list_[0].append('inner_item') - assert isinstance(list_._parent[0], Parameter) + assert isinstance(actor.list_[0], Parameter) assert len(list_) == 1 assert list_[0][0] == 'inner_item' list_[0].append('new_item') - assert isinstance(list_._parent[0], Parameter) + assert isinstance(actor.list_[0], Parameter) assert len(list_) == 1 assert list_[0][1] == 'new_item'