Adds model mixin for {to,from}_dict functionality
Implements ModelDictMixin, which is an alternative to DictBase that does not force a module to have an "extra" field. It also gets away from the idea that we need to keep a list of attibutes, named `attributes`, on each model definition. Change-Id: Id2c208ee9be4cc17b1b6444c5e0558952571163b Fixes-bug: #1265071
This commit is contained in:
parent
ddea84840b
commit
d867815929
@ -144,6 +144,19 @@ class DictBase(models.ModelBase):
|
||||
return getattr(self, key)
|
||||
|
||||
|
||||
class ModelDictMixin(object):
|
||||
|
||||
@classmethod
|
||||
def from_dict(cls, d):
|
||||
"""Returns a model instance from a dictionary."""
|
||||
return cls(**d)
|
||||
|
||||
def to_dict(self):
|
||||
"""Returns the model's attributes as a dictionary."""
|
||||
names = (column.name for column in self.__table__.columns)
|
||||
return dict((name, getattr(self, name)) for name in names)
|
||||
|
||||
|
||||
@contextlib.contextmanager
|
||||
def transaction(expire_on_commit=False):
|
||||
"""Return a SQLAlchemy session in a scoped transaction."""
|
||||
|
@ -55,7 +55,7 @@ from keystone.common import kvs
|
||||
from keystone.common.kvs import core as kvs_core
|
||||
from keystone.common import sql
|
||||
from keystone.common.sql import migration_helpers
|
||||
from keystone.common import utils
|
||||
from keystone.common import utils as common_utils
|
||||
from keystone import config
|
||||
from keystone import exception
|
||||
from keystone import notifications
|
||||
@ -132,12 +132,12 @@ def checkout_vendor(repo, rev):
|
||||
return revdir
|
||||
|
||||
if not os.path.exists(revdir):
|
||||
utils.git('clone', repo, revdir)
|
||||
common_utils.git('clone', repo, revdir)
|
||||
|
||||
os.chdir(revdir)
|
||||
utils.git('checkout', '-q', 'master')
|
||||
utils.git('pull', '-q')
|
||||
utils.git('checkout', '-q', rev)
|
||||
common_utils.git('checkout', '-q', 'master')
|
||||
common_utils.git('pull', '-q')
|
||||
common_utils.git('checkout', '-q', rev)
|
||||
|
||||
# write out a modified time
|
||||
with open(modcheck, 'w') as fd:
|
||||
|
0
keystone/tests/unit/__init__.py
Normal file
0
keystone/tests/unit/__init__.py
Normal file
0
keystone/tests/unit/common/__init__.py
Normal file
0
keystone/tests/unit/common/__init__.py
Normal file
52
keystone/tests/unit/common/test_sql_core.py
Normal file
52
keystone/tests/unit/common/test_sql_core.py
Normal file
@ -0,0 +1,52 @@
|
||||
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
||||
# not use this file except in compliance with the License. You may obtain
|
||||
# a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
||||
|
||||
|
||||
from sqlalchemy.ext import declarative
|
||||
import testtools
|
||||
|
||||
from keystone.common import sql
|
||||
from keystone.tests import utils
|
||||
|
||||
|
||||
ModelBase = declarative.declarative_base()
|
||||
|
||||
|
||||
class TestModel(ModelBase, sql.ModelDictMixin):
|
||||
__tablename__ = 'testmodel'
|
||||
id = sql.Column(sql.String(64), primary_key=True)
|
||||
text = sql.Column(sql.String(64), nullable=False)
|
||||
|
||||
|
||||
class TestModelDictMixin(testtools.TestCase):
|
||||
|
||||
def test_creating_a_model_instance_from_a_dict(self):
|
||||
d = {'id': utils.new_uuid(), 'text': utils.new_uuid()}
|
||||
m = TestModel.from_dict(d)
|
||||
self.assertEqual(m.id, d['id'])
|
||||
self.assertEqual(m.text, d['text'])
|
||||
|
||||
def test_creating_a_dict_from_a_model_instance(self):
|
||||
m = TestModel(id=utils.new_uuid(), text=utils.new_uuid())
|
||||
d = m.to_dict()
|
||||
self.assertEqual(m.id, d['id'])
|
||||
self.assertEqual(m.text, d['text'])
|
||||
|
||||
def test_creating_a_model_instance_from_an_invalid_dict(self):
|
||||
d = {'id': utils.new_uuid(), 'text': utils.new_uuid(), 'extra': None}
|
||||
self.assertRaises(TypeError, TestModel.from_dict, d)
|
||||
|
||||
def test_creating_a_dict_from_a_model_instance_that_has_extra_attrs(self):
|
||||
expected = {'id': utils.new_uuid(), 'text': utils.new_uuid()}
|
||||
m = TestModel(id=expected['id'], text=expected['text'])
|
||||
m.extra = 'this should not be in the dictionary'
|
||||
self.assertEqual(m.to_dict(), expected)
|
20
keystone/tests/utils.py
Normal file
20
keystone/tests/utils.py
Normal file
@ -0,0 +1,20 @@
|
||||
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
||||
# not use this file except in compliance with the License. You may obtain
|
||||
# a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
||||
|
||||
"""Useful utilities for tests."""
|
||||
|
||||
import uuid
|
||||
|
||||
|
||||
def new_uuid():
|
||||
"""Return a string UUID."""
|
||||
return uuid.uuid4().hex
|
Loading…
Reference in New Issue
Block a user