Add set_value method.
This commit is contained in:
@@ -350,6 +350,9 @@ class SchemaType(object):
|
||||
assert paths == [name], "paths should be [name] for leaf nodes."
|
||||
return fstruct[name]
|
||||
|
||||
def set_value(self, node, appstruct, path, value):
|
||||
raise AssertionError("Can't call 'set_value' on a leaf node.")
|
||||
|
||||
class Mapping(SchemaType):
|
||||
""" A type which represents a mapping of names to nodes.
|
||||
|
||||
@@ -487,6 +490,16 @@ class Mapping(SchemaType):
|
||||
def unflatten(self, node, paths, fstruct):
|
||||
return _unflatten_mapping(node, paths, fstruct)
|
||||
|
||||
def set_value(self, node, appstruct, path, value):
|
||||
if '.' in path:
|
||||
next_name, rest = path.split('.', 1)
|
||||
next_node = node[next_name]
|
||||
next_appstruct = appstruct[next_name]
|
||||
appstruct[next_name] = next_node.typ.set_value(
|
||||
next_node, next_appstruct, rest, value)
|
||||
else:
|
||||
appstruct[path] = value
|
||||
return appstruct
|
||||
|
||||
class Positional(object):
|
||||
"""
|
||||
@@ -587,6 +600,25 @@ class Tuple(Positional, SchemaType):
|
||||
appstruct.append(mapstruct[subnode.name])
|
||||
return tuple(appstruct)
|
||||
|
||||
def set_value(self, node, appstruct, path, value):
|
||||
appstruct = list(appstruct)
|
||||
if '.' in path:
|
||||
next_name, rest = path.split('.', 1)
|
||||
else:
|
||||
next_name, rest = path, None
|
||||
for index, next_node in enumerate(node.children):
|
||||
if next_node.name == next_name:
|
||||
break
|
||||
else:
|
||||
raise KeyError(next_name)
|
||||
if rest is not None:
|
||||
next_appstruct = appstruct[index]
|
||||
appstruct[index] = next_node.typ.set_value(
|
||||
next_node, next_appstruct, rest, value)
|
||||
else:
|
||||
appstruct[index] = value
|
||||
return tuple(appstruct)
|
||||
|
||||
class Sequence(Positional, SchemaType):
|
||||
"""
|
||||
A type which represents a variable-length sequence of nodes,
|
||||
@@ -737,6 +769,18 @@ class Sequence(Positional, SchemaType):
|
||||
get_child, rewrite_subpath)
|
||||
return [mapstruct[str(index)] for index in xrange(len(mapstruct))]
|
||||
|
||||
def set_value(self, node, appstruct, path, value):
|
||||
if '.' in path:
|
||||
next_name, rest = path.split('.', 1)
|
||||
index = int(next_name)
|
||||
next_node = node.children[0]
|
||||
next_appstruct = appstruct[index]
|
||||
appstruct[index] = next_node.typ.set_value(
|
||||
next_node, next_appstruct, rest, value)
|
||||
else:
|
||||
index = int(path)
|
||||
appstruct[index] = value
|
||||
return appstruct
|
||||
|
||||
Seq = Sequence
|
||||
|
||||
@@ -1461,6 +1505,11 @@ class SchemaNode(object):
|
||||
paths = sorted(fstruct.keys())
|
||||
return self.typ.unflatten(self, paths, fstruct)
|
||||
|
||||
def set_value(self, appstruct, dotted_name, value):
|
||||
""" Uses the schema to set a value in an appstruct from a dotted_name
|
||||
path. """
|
||||
self.typ.set_value(self, appstruct, dotted_name, value)
|
||||
|
||||
def deserialize(self, cstruct=null):
|
||||
""" Deserialize the :term:`cstruct` into an :term:`appstruct` based
|
||||
on the schema, run this :term:`appstruct` through the
|
||||
|
@@ -342,6 +342,11 @@ class TestSchemaType(unittest.TestCase):
|
||||
result = typ.unflatten(node, ['node'], {'node': 'appstruct'})
|
||||
self.assertEqual(result, 'appstruct')
|
||||
|
||||
def test_set_value(self):
|
||||
typ = self._makeOne()
|
||||
self.assertRaises(
|
||||
AssertionError, typ.set_value, None, None, None, None)
|
||||
|
||||
class TestMapping(unittest.TestCase):
|
||||
def _makeOne(self, *arg, **kw):
|
||||
from colander import Mapping
|
||||
@@ -534,6 +539,14 @@ class TestMapping(unittest.TestCase):
|
||||
self.assertEqual(result, {
|
||||
'one': {'a': 1, 'b': 2}, 'two': {'c': 3, 'd': 4}})
|
||||
|
||||
def test_set_value(self):
|
||||
typ = self._makeOne()
|
||||
node1 = DummySchemaNode(typ, name='node1')
|
||||
node2 = DummySchemaNode(typ, name='node2')
|
||||
node1.children = [node2]
|
||||
appstruct = {'node2': {'foo': 'foo', 'baz': 'baz'}}
|
||||
typ.set_value(node1, appstruct, 'node2.foo', 'bar')
|
||||
self.assertEqual(appstruct, {'node2': {'foo': 'bar', 'baz': 'baz'}})
|
||||
|
||||
class TestTuple(unittest.TestCase):
|
||||
def _makeOne(self):
|
||||
@@ -690,6 +703,35 @@ class TestTuple(unittest.TestCase):
|
||||
{'node': (1, 2), 'node.a': 1, 'node.b': 2})
|
||||
self.assertEqual(result, (1, 2))
|
||||
|
||||
def test_set_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))
|
||||
result = typ.set_value(node, appstruct, 'bar.c', 34)
|
||||
self.assertEqual(result, ((1, 2), (34, 4)))
|
||||
|
||||
def test_set_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.set_value, node, (1, 2), 'foobar', 34)
|
||||
|
||||
class TestSequence(unittest.TestCase):
|
||||
def _makeOne(self, **kw):
|
||||
from colander import Sequence
|
||||
@@ -821,6 +863,16 @@ class TestSequence(unittest.TestCase):
|
||||
{'node.0': 'a', 'node.1': 'b'})
|
||||
self.assertEqual(result, ['a', 'b'])
|
||||
|
||||
def test_setvalue(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]]
|
||||
typ.set_value(node1, appstruct, '1.0', 34)
|
||||
self.assertEqual(appstruct, [[1, 2], [34, 4]])
|
||||
|
||||
|
||||
class TestString(unittest.TestCase):
|
||||
def _makeOne(self, encoding=None):
|
||||
@@ -2110,6 +2162,19 @@ class TestFunctional(object):
|
||||
schema.unflatten(schema.flatten(appstruct)),
|
||||
appstruct)
|
||||
|
||||
def test_set_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()
|
||||
schema.set_value(appstruct, 'seq2.1.key', 6)
|
||||
self.assertEqual(appstruct['seq2'][1], {'key':6, 'key2':4})
|
||||
|
||||
def test_invalid_asdict(self):
|
||||
expected = {
|
||||
'schema.int': '20 is greater than maximum value 10',
|
||||
|
Reference in New Issue
Block a user