Add get_value method.

This commit is contained in:
Chris Rossi
2011-07-27 11:35:08 -04:00
parent 38d953a9e1
commit 6948236ba4
2 changed files with 107 additions and 0 deletions

View File

@@ -353,6 +353,9 @@ class SchemaType(object):
def set_value(self, node, appstruct, path, value):
raise AssertionError("Can't call 'set_value' on a leaf node.")
def get_value(self, node, appstruct, path):
raise AssertionError("Can't call 'set_value' on a leaf node.")
class Mapping(SchemaType):
""" A type which represents a mapping of names to nodes.
@@ -501,6 +504,14 @@ class Mapping(SchemaType):
appstruct[path] = value
return appstruct
def get_value(self, node, appstruct, path):
if '.' in path:
name, rest = path.split('.', 1)
next_node = node[name]
return next_node.typ.get_value(next_node, appstruct[name], rest)
return appstruct[path]
class Positional(object):
"""
Marker abstract base class meaning 'this type has children which
@@ -619,6 +630,21 @@ class Tuple(Positional, SchemaType):
appstruct[index] = value
return tuple(appstruct)
def get_value(self, node, appstruct, path):
if '.' in path:
name, rest = path.split('.', 1)
else:
name, rest = path, None
for index, next_node in enumerate(node.children):
if next_node.name == name:
break
else:
raise KeyError(name)
if rest is not None:
return next_node.typ.get_value(next_node, appstruct[index], rest)
return appstruct[index]
class Sequence(Positional, SchemaType):
"""
A type which represents a variable-length sequence of nodes,
@@ -782,6 +808,14 @@ class Sequence(Positional, SchemaType):
appstruct[index] = value
return appstruct
def get_value(self, node, appstruct, path):
if '.' in path:
name, rest = path.split('.', 1)
index = int(name)
next_node = node.children[0]
return next_node.typ.get_value(next_node, appstruct[index], rest)
return appstruct[int(path)]
Seq = Sequence
class String(SchemaType):
@@ -1510,6 +1544,11 @@ class SchemaNode(object):
path. """
self.typ.set_value(self, appstruct, dotted_name, value)
def get_value(self, appstruct, dotted_name):
""" Traverses the appstruct using the schema and retrieves the value
specified by the dotted_name path."""
return self.typ.get_value(self, appstruct, dotted_name)
def deserialize(self, cstruct=null):
""" Deserialize the :term:`cstruct` into an :term:`appstruct` based
on the schema, run this :term:`appstruct` through the

View File

@@ -347,6 +347,11 @@ class TestSchemaType(unittest.TestCase):
self.assertRaises(
AssertionError, typ.set_value, None, None, None, None)
def test_get_value(self):
typ = self._makeOne()
self.assertRaises(
AssertionError, typ.get_value, None, None, None)
class TestMapping(unittest.TestCase):
def _makeOne(self, *arg, **kw):
from colander import Mapping
@@ -548,6 +553,17 @@ class TestMapping(unittest.TestCase):
typ.set_value(node1, appstruct, 'node2.foo', 'bar')
self.assertEqual(appstruct, {'node2': {'foo': 'bar', 'baz': 'baz'}})
def test_get_value(self):
typ = self._makeOne()
node1 = DummySchemaNode(typ, name='node1')
node2 = DummySchemaNode(typ, name='node2')
node1.children = [node2]
appstruct = {'node2': {'foo': 'bar', 'baz': 'baz'}}
self.assertEqual(typ.get_value(node1, appstruct, 'node2'),
{'foo': 'bar', 'baz': 'baz'})
self.assertEqual(typ.get_value(node1, appstruct, 'node2.foo'), 'bar')
class TestTuple(unittest.TestCase):
def _makeOne(self):
from colander import Tuple
@@ -732,6 +748,35 @@ class TestTuple(unittest.TestCase):
self.assertRaises(
KeyError, typ.set_value, node, (1, 2), 'foobar', 34)
def test_get_value(self):
typ = self._makeOne()
node = DummySchemaNode(typ, name='node')
node.children = [
DummySchemaNode(typ, name='foo'),
DummySchemaNode(typ, name='bar')
]
node['foo'].children = [
DummySchemaNode(None, name='a'),
DummySchemaNode(None, name='b'),
]
node['bar'].children = [
DummySchemaNode(None, name='c'),
DummySchemaNode(None, name='d'),
]
appstruct = ((1, 2), (3, 4))
self.assertEqual(typ.get_value(node, appstruct, 'foo'), (1, 2))
self.assertEqual(typ.get_value(node, appstruct, 'foo.b'), 2)
def test_get_value_bad_path(self):
typ = self._makeOne()
node = DummySchemaNode(typ, name='node')
node.children = [
DummySchemaNode(None, name='foo'),
DummySchemaNode(None, name='bar')
]
self.assertRaises(
KeyError, typ.get_value, node, (1, 2), 'foobar')
class TestSequence(unittest.TestCase):
def _makeOne(self, **kw):
from colander import Sequence
@@ -873,6 +918,15 @@ class TestSequence(unittest.TestCase):
typ.set_value(node1, appstruct, '1.0', 34)
self.assertEqual(appstruct, [[1, 2], [34, 4]])
def test_getvalue(self):
typ = self._makeOne()
node1 = DummySchemaNode(typ, name='seq1')
node2 = DummySchemaNode(typ, name='seq2')
node1.children = [node2]
node2.children = DummySchemaNode(None, name='items')
appstruct = [[1, 2], [3, 4]]
self.assertEqual(typ.get_value(node1, appstruct, '1'), [3, 4])
self.assertEqual(typ.get_value(node1, appstruct, '1.0'), 3)
class TestString(unittest.TestCase):
def _makeOne(self, encoding=None):
@@ -2175,6 +2229,20 @@ class TestFunctional(object):
schema.set_value(appstruct, 'seq2.1.key', 6)
self.assertEqual(appstruct['seq2'][1], {'key':6, 'key2':4})
def test_get_value(self):
import colander
appstruct = {
'int':10,
'ob':colander.tests,
'seq':[(1, 's'),(2, 's'), (3, 's'), (4, 's')],
'seq2':[{'key':1, 'key2':2}, {'key':3, 'key2':4}],
'tup':(1, 's'),
}
schema = self._makeSchema()
self.assertEqual(schema.get_value(appstruct, 'seq'),
[(1, 's'),(2, 's'), (3, 's'), (4, 's')])
self.assertEqual(schema.get_value(appstruct, 'seq2.1.key'), 3)
def test_invalid_asdict(self):
expected = {
'schema.int': '20 is greater than maximum value 10',