You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@ariatosca.apache.org by mx...@apache.org on 2017/01/31 10:10:53 UTC

incubator-ariatosca git commit: code review 1 [Forced Update!]

Repository: incubator-ariatosca
Updated Branches:
  refs/heads/ARIA-66-Convert-custom-parser-fields-into-sqla-based-fields 66347e84b -> 57dcaa884 (forced update)


code review 1


Project: http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/commit/57dcaa88
Tree: http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/tree/57dcaa88
Diff: http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/diff/57dcaa88

Branch: refs/heads/ARIA-66-Convert-custom-parser-fields-into-sqla-based-fields
Commit: 57dcaa884aebc150240151986fbb1fcc459fd734
Parents: d8359e6
Author: mxmrlv <mx...@gmail.com>
Authored: Tue Jan 31 11:50:03 2017 +0200
Committer: mxmrlv <mx...@gmail.com>
Committed: Tue Jan 31 12:10:35 2017 +0200

----------------------------------------------------------------------
 aria/storage/type.py                  | 80 ++++++++++++++++++++----------
 tests/storage/test_instrumentation.py | 53 +++++++++++++++++++-
 tests/storage/test_structures.py      | 38 +++++++-------
 3 files changed, 124 insertions(+), 47 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/blob/57dcaa88/aria/storage/type.py
----------------------------------------------------------------------
diff --git a/aria/storage/type.py b/aria/storage/type.py
index 8fb02c6..a713d9c 100644
--- a/aria/storage/type.py
+++ b/aria/storage/type.py
@@ -23,7 +23,7 @@ from sqlalchemy import (
 )
 from sqlalchemy.ext import mutable
 
-from aria.storage import exceptions
+from . import exceptions
 
 
 class _MutableType(TypeDecorator):
@@ -126,9 +126,6 @@ class _MutableDict(mutable.MutableDict):
 
 
 class _StrictListMixin(object):
-    ANY_TYPE = 'any_type'
-
-    _item_cls = ANY_TYPE
 
     @classmethod
     def coerce(cls, key, value):
@@ -175,72 +172,105 @@ class _MutableList(mutable.MutableList):
     @classmethod
     def coerce(cls, key, value):
         "Convert plain dictionaries to MutableDict."
-
         try:
-            if not isinstance(value, cls):
-                if isinstance(value, list):
-                    return cls(value)
-
-                return mutable.Mutable.coerce(key, value)
-            else:
-                return value
-
+            return mutable.MutableList.coerce(key, value)
         except ValueError as e:
             raise exceptions.StorageError('SQL Storage error: {0}'.format(str(e)))
 
-StrictDictID = namedtuple('strict_dict_id', 'key_cls, value_cls')
+StrictDictID = namedtuple('StrictDictID', 'key_cls, value_cls')
+StrictValue = namedtuple('StrictValue', 'type_cls, listener_cls')
 
 
 class _StrictDict(object):
+    """
+    This entire class functions as a factory for strict dicts and their listeners.
+    No type class, and no listener type class is created (and associated) more than once. If a
+    relevant type class exists it is returned.
+    """
     _strict_map = {}
 
-    def __call__(self, key_cls=None, value_cls=None, *args, **kwargs):
+    def __call__(self, key_cls=None, value_cls=None):
         strict_dict_map_key = StrictDictID(key_cls=key_cls, value_cls=value_cls)
         if strict_dict_map_key not in self._strict_map:
+            # Creating the type class itself. this class would be returned (used by the sqlalchemy
+            # Column).
             strict_dict_cls = type(
                 'StrictDict_{0}_{1}'.format(key_cls.__name__, value_cls.__name__),
                 (Dict, ),
                 {}
             )
-            type(
+            # Creating the type listening class and associating it with the newly created type.
+            # The new class inherits from both the _MutableList class and the _StrictListMixin,
+            # while setting the necessary _key_cls and _value_cls as class attributes.
+            listener_cls = type(
                 'StrictMutableDict_{0}_{1}'.format(key_cls.__name__, value_cls.__name__),
                 (_StrictDictMixin, _MutableDict),
                 {'_key_cls': key_cls, '_value_cls': value_cls}
-            ).associate_with(strict_dict_cls)
-            self._strict_map[strict_dict_map_key] = strict_dict_cls
+            )
+            listener_cls.associate_with(strict_dict_cls)
+            self._strict_map[strict_dict_map_key] = StrictValue(type_cls=strict_dict_cls,
+                                                                listener_cls=listener_cls)
 
-        return self._strict_map[strict_dict_map_key]
+        return self._strict_map[strict_dict_map_key].type_cls
 
 StrictDict = _StrictDict()
 
 
 class _StrictList(object):
+    """
+    This entire class functions as a factory for strict dicts and their listeners.
+    No type class, and no listener type class is created (and associated) more than once. If a
+    relevant type class exists it is returned.
+    """
     _strict_map = {}
 
     def __call__(self, item_cls=None):
+
         if item_cls not in self._strict_map:
+            # Creating the type class itself. this class would be returned (used by the sqlalchemy
+            # Column).
             strict_list_cls = type(
                 'StrictList_{0}'.format(item_cls.__name__),
                 (List, ),
                 {}
             )
-            type(
+            # Creating the type listening class and associating it with the newly created type.
+            # The new class inherits from both the _MutableList class and the _StrictListMixin,
+            # while setting the necessary _item_cls as class attribute.
+            listener_cls = type(
                 'StrictMutableList_{0}'.format(item_cls.__name__),
                 (_StrictListMixin, _MutableList),
                 {'_item_cls': item_cls}
-            ).associate_with(strict_list_cls)
-            self._strict_map[item_cls] = strict_list_cls
+            )
+            self._strict_map[item_cls] = StrictValue(type_cls=strict_list_cls,
+                                                     listener_cls=listener_cls)
 
-        return self._strict_map[item_cls]
+        return self._strict_map[item_cls].type_cls
 
 StrictList = _StrictList()
 
+
 def _mutable_association_listener(mapper, cls):
+    strict_dict_type_to_listener = \
+        dict((v.type_cls, v.listener_cls) for v in _StrictDict._strict_map.values())
+
+    strict_list_type_to_listener = \
+        dict((v.type_cls, v.listener_cls) for v in _StrictList._strict_map.values())
+
     for prop in mapper.column_attrs:
         column_type = prop.columns[0].type
-        if isinstance(column_type, Dict):
+        # Dict Listeners
+        if any(isinstance(column_type, v) for v in strict_dict_type_to_listener):
+            strict_dict_type_to_listener[type(column_type)].associate_with_attribute(
+                getattr(cls, prop.key))
+        elif isinstance(column_type, Dict):
             _MutableDict.associate_with_attribute(getattr(cls, prop.key))
-        if isinstance(column_type, List):
+
+        # List Listeners
+        if any(isinstance(column_type, v) for v in strict_list_type_to_listener):
+            strict_list_type_to_listener[type(column_type)].associate_with_attribute(
+                getattr(cls, prop.key))
+        elif isinstance(column_type, List):
             _MutableList.associate_with_attribute(getattr(cls, prop.key))
 _LISTENER_ARGS = (mutable.mapper, 'mapper_configured', _mutable_association_listener)
 

http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/blob/57dcaa88/tests/storage/test_instrumentation.py
----------------------------------------------------------------------
diff --git a/tests/storage/test_instrumentation.py b/tests/storage/test_instrumentation.py
index 8b826e9..9b4da4f 100644
--- a/tests/storage/test_instrumentation.py
+++ b/tests/storage/test_instrumentation.py
@@ -22,7 +22,8 @@ from aria.storage import (
     type as aria_type,
     ModelStorage,
     sql_mapi,
-    instrumentation
+    instrumentation,
+    exceptions
 )
 from ..storage import get_sqlite_api_kwargs, release_sqlite_storage
 
@@ -275,6 +276,47 @@ class TestInstrumentation(object):
         instruments_holder.append(instrument)
         return instrument
 
+    def test_track_changes_to_strict_dict(self, storage):
+        model_kwargs = dict(strict_dict={'key': 'value'},
+                            strict_list=['item'])
+        mode_instance = StrictMockModel(**model_kwargs)
+        storage.strict_mock_model.put(mode_instance)
+
+        instrument = self._track_changes({
+            StrictMockModel.strict_dict: dict,
+            StrictMockModel.strict_list: list,
+        })
+
+        assert not instrument.tracked_changes
+
+        storage_model_instance = storage.strict_mock_model.get(mode_instance.id)
+
+        with pytest.raises(exceptions.StorageError):
+            storage_model_instance.strict_dict = {1: 1}
+
+        with pytest.raises(exceptions.StorageError):
+            storage_model_instance.strict_dict = {'hello': 1}
+
+        with pytest.raises(exceptions.StorageError):
+            storage_model_instance.strict_dict = {1: 'hello'}
+
+        storage_model_instance.strict_dict = {'hello': 'world'}
+        assert storage_model_instance.strict_dict == {'hello': 'world'}
+
+        with pytest.raises(exceptions.StorageError):
+            storage_model_instance.strict_list = [1]
+        storage_model_instance.strict_list = ['hello']
+        assert storage_model_instance.strict_list == ['hello']
+
+        assert instrument.tracked_changes == {
+            'strict_mock_model': {
+                mode_instance.id: {
+                    'strict_dict': Value(STUB, {'hello': 'world'}),
+                    'strict_list': Value(STUB, ['hello']),
+                }
+            },
+        }
+
 
 @pytest.fixture(autouse=True)
 def restore_instrumentation():
@@ -289,7 +331,7 @@ def storage():
     result = ModelStorage(
         api_cls=sql_mapi.SQLAlchemyModelAPI,
         api_kwargs=get_sqlite_api_kwargs(),
-        items=(MockModel1, MockModel2))
+        items=(MockModel1, MockModel2, StrictMockModel))
     yield result
     release_sqlite_storage(result)
 
@@ -311,3 +353,10 @@ class MockModel1(model.DeclarativeBase, _MockModel):
 
 class MockModel2(model.DeclarativeBase, _MockModel):
     __tablename__ = 'mock_model2'
+
+
+class StrictMockModel(model.DeclarativeBase):
+    __tablename__ = 'strict_mock_model'
+
+    strict_dict = Column(aria_type.StrictDict(basestring, basestring))
+    strict_list = Column(aria_type.StrictList(basestring))

http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/blob/57dcaa88/tests/storage/test_structures.py
----------------------------------------------------------------------
diff --git a/tests/storage/test_structures.py b/tests/storage/test_structures.py
index 7e34b17..0223a98 100644
--- a/tests/storage/test_structures.py
+++ b/tests/storage/test_structures.py
@@ -236,42 +236,40 @@ def test_strict_dict():
 
     strict_class = StrictClass()
 
-    def assert_strict(sd, after_assignment=False):
-        if after_assignment:
-            with pytest.raises(exceptions.StorageError):
-                sd.strict_dict['key'] = None
-            with pytest.raises(exceptions.StorageError):
-                sd.strict_dict[None] = 'value'
-            with pytest.raises(exceptions.StorageError):
-                sd.strict_dict[None] = None
-
+    def assert_strict(sc):
         with pytest.raises(exceptions.StorageError):
-            sd.strict_dict = {'key': None}
+            sc.strict_dict = {'key': 1}
 
         with pytest.raises(exceptions.StorageError):
-            sd.strict_dict = {None: 'value'}
+            sc.strict_dict = {1: 'value'}
 
         with pytest.raises(exceptions.StorageError):
-            sd.strict_dict = {None: None}
+            sc.strict_dict = {1: 1}
 
     assert_strict(strict_class)
     strict_class.strict_dict = {'key': 'value'}
     assert strict_class.strict_dict == {'key': 'value'}
-    assert_strict(strict_class, after_assignment=True)
+
+    assert_strict(strict_class)
+    with pytest.raises(exceptions.StorageError):
+        strict_class.strict_dict['key'] = 1
+    with pytest.raises(exceptions.StorageError):
+        strict_class.strict_dict[1] = 'value'
+    with pytest.raises(exceptions.StorageError):
+        strict_class.strict_dict[1] = 1
 
 
 def test_strict_list():
     strict_class = StrictClass()
 
-    def assert_strict(sd, after_assignment=False):
-        if after_assignment:
-            with pytest.raises(exceptions.StorageError):
-                sd.strict_list[0] = None
-
+    def assert_strict(sc):
         with pytest.raises(exceptions.StorageError):
-            sd.strict_list = [None]
+            sc.strict_list = [1]
 
     assert_strict(strict_class)
     strict_class.strict_list = ['item']
     assert strict_class.strict_list == ['item']
-    assert_strict(strict_class, after_assignment=True)
+
+    assert_strict(strict_class)
+    with pytest.raises(exceptions.StorageError):
+        strict_class.strict_list[0] = 1