Skip to content

Commit

Permalink
create get_component_by_id() which retrieves a model instance by its …
Browse files Browse the repository at this point in the history
…identifier
  • Loading branch information
artgoldberg committed Feb 7, 2017
1 parent aa6b1c1 commit 3904db0
Show file tree
Hide file tree
Showing 3 changed files with 61 additions and 27 deletions.
51 changes: 29 additions & 22 deletions tests/schema/test_utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,22 +27,25 @@ class Leaf(core.Model):

class TestUtils(unittest.TestCase):

def setUp(self):
self.root = Root(id='root')
self.nodes = [
Node(root=self.root, id='node-0'),
Node(root=self.root, id='node-1'),
]
self.leaves = [
Leaf(node=self.nodes[0], id='leaf-0-0'),
Leaf(node=self.nodes[0], id='leaf-0-1'),
Leaf(node=self.nodes[1], id='leaf-1-0'),
Leaf(node=self.nodes[1], id='leaf-1-1'),
]

def test_get_attribute_by_verbose_name(self):
self.assertEqual(utils.get_attribute_by_verbose_name(Root, 'Identifier'), Root.Meta.attributes['id'])
self.assertEqual(utils.get_attribute_by_verbose_name(Root, 'Identifier2'), None)

def test_group_objects_by_model(self):
root = Root(id='root')
nodes = [
Node(root=root, id='node-0'),
Node(root=root, id='node-1'),
]
leaves = [
Leaf(node=nodes[0], id='leaf-0-0'),
Leaf(node=nodes[0], id='leaf-0-1'),
Leaf(node=nodes[1], id='leaf-1-0'),
Leaf(node=nodes[1], id='leaf-1-1'),
]
(root, nodes, leaves) = (self.root, self.nodes, self.leaves)
objects = set((root,)) | set(nodes) | set(leaves)
grouped_objects = utils.group_objects_by_model(objects)
self.assertEqual(grouped_objects, {
Expand All @@ -52,17 +55,7 @@ def test_group_objects_by_model(self):
})

def test_get_related_errors(self):
root = Root(id='root')
nodes = [
Node(root=root, id='node-0'),
Node(root=root, id='node-1'),
]
leaves = [
Leaf(node=nodes[0], id='leaf-0-0'),
Leaf(node=nodes[0], id='leaf-0-1'),
Leaf(node=nodes[1], id='leaf-1-0'),
Leaf(node=nodes[1], id='leaf-1-1'),
]
(root, nodes, leaves) = (self.root, self.nodes, self.leaves)

errors = utils.get_related_errors(root)
self.assertEqual(set((x.object for x in errors.invalid_objects)), set((root, )) | set(nodes))
Expand All @@ -74,3 +67,17 @@ def test_get_related_errors(self):
self.assertEqual(len(errors_by_model[Node]), 2)

self.assertIsInstance(str(errors), string_types)

def test_get_component_by_id(self):
class Test(core.Model):
val = core.StringAttribute()

(root, nodes, leaves) = (self.root, self.nodes, self.leaves)
self.assertEqual(utils.get_component_by_id(nodes, 'node-0'), nodes[0])
self.assertEqual(utils.get_component_by_id(nodes, 'node-1'), nodes[1])
self.assertEqual(utils.get_component_by_id(nodes, 'x'), None)

test = Test(val='x')
self.assertRaises(AttributeError,
lambda: utils.get_component_by_id([test], 'x'))
self.assertEqual(utils.get_component_by_id([test], 'x', identifier='val'), test)
13 changes: 8 additions & 5 deletions wc_utils/schema/core.py
Original file line number Diff line number Diff line change
Expand Up @@ -251,19 +251,22 @@ def init_related_attributes(cls):
attr.related_class = related_class

# setup related attributes on related classes
if attr.name in cls.__dict__ and attr.related_name and isinstance(attr.related_class, type) and issubclass(attr.related_class, Model):
if attr.name in cls.__dict__ and attr.related_name and \
isinstance(attr.related_class, type) and issubclass(attr.related_class, Model):
related_classes = chain([attr.related_class], get_subclasses(attr.related_class))
for related_class in related_classes:
# check that related class has primary attributes

if isinstance(attr, (OneToManyAttribute, ManyToManyAttribute)) and \
attr.__class__ is not OneToManyAttribute and attr.__class__ is not ManyToManyAttribute and \
'serialize' in attr.__class__.__dict__ and 'deserialize' in attr.__class__.__dict__:
attr.__class__ is not OneToManyAttribute and \
attr.__class__ is not ManyToManyAttribute and \
'serialize' in attr.__class__.__dict__ and \
'deserialize' in attr.__class__.__dict__:
pass
elif not related_class.Meta.primary_attribute:
if related_class.Meta.tabular_orientation == TabularOrientation.inline:
warnings.warn('Related class {} must have a primary attribute'.format(
related_class.__name__))
warnings.warn('Primary class: {}: Related class {} must have a primary attribute'.format(
attr.primary_class.__name__, related_class.__name__))
else:
raise ValueError('Related class {} must have a primary attribute'.format(
related_class.__name__))
Expand Down
24 changes: 24 additions & 0 deletions wc_utils/schema/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -59,3 +59,27 @@ def get_related_errors(object):
"""
objects = set((object,)) | object.get_related()
return Validator().run(objects)


def get_component_by_id(models, id, identifier='id'):
''' Retrieve a model instance by its identifier
Args:
model (:obj:list of `Model`): an iterable of `Model` objects
id (:obj:`str`): the identifier being sought
identifier (:obj:`str`, optional): the name of the identifier attribute
Returns:
:obj:`Model`: the retrieved Model instance if found, or None
Raises:
:obj:`AttributeError`: if `model` does not have the attribute specified by `identifier`
'''
for model in models:
try:
if getattr(model, identifier) == id:
return model
except AttributeError as e:
raise AttributeError("{} does not have the attribute '{}'".format(model.__class__.__name__,
identifier))
return None

0 comments on commit 3904db0

Please sign in to comment.