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