Manipulating Data Structures

Colander schemas have some utility functions which can be used to manipulate an appstruct or a cstruct. Nested data structures can be flattened into a single dictionary or a single flattened dictionary can be used to produce a nested data structure. Values of particular nodes can also be set or retrieved based on a flattened path spec.

Flattening a Data Structure

colander.SchemaNode.flatten() can be used to convert a datastructure with nested dictionaries and/or lists into a single flattened dictionary where each key in the dictionary is a dotted name path to the node in the nested structure.

Consider the following schema:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
import colander

class Friend(colander.TupleSchema):
    rank = colander.SchemaNode(colander.Int(),
                               validator=colander.Range(0, 9999))
    name = colander.SchemaNode(colander.String())

class Phone(colander.MappingSchema):
    location = colander.SchemaNode(colander.String(),
                                  validator=colander.OneOf(['home', 'work']))
    number = colander.SchemaNode(colander.String())

class Friends(colander.SequenceSchema):
    friend = Friend()

class Phones(colander.SequenceSchema):
    phone = Phone()

class Person(colander.MappingSchema):
    name = colander.SchemaNode(colander.String())
    age = colander.SchemaNode(colander.Int(),
                             validator=colander.Range(0, 200))
    friends = Friends()
    phones = Phones()

Consider also a particular serialization of data using that schema:

1
2
3
4
5
6
7
  appstruct = {
  'name':'keith',
  'age':20,
  'friends':[(1, 'jim'),(2, 'bob'), (3, 'joe'), (4, 'fred')],
  'phones':[{'location':'home', 'number':'555-1212'},
            {'location':'work', 'number':'555-8989'},],
  }

This data can be flattened:

1
2
  schema = Person()
  fstruct = schema.flatten(appstruct)

The resulting flattened structure would look like this:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
  {
  'name': 'keith',
  'age': 20,
  'friends.0.rank': 1,
  'friends.0.name': 'jim',
  'friends.1.rank': 2,
  'friends.1.name': 'bob',
  'friends.2.rank': 3,
  'friends.2.name': 'joe',
  'friends.3.rank': 4,
  'friends.3.name': 'fred',
  'phones.0.location': 'home',
  'phones.0.number': '555-1212',
  'phones.1.location': 'work',
  'phones.1.number': '555-8989',
  }

The process can be reversed using colander.SchemaNode.unflatten():

1
  appstruct = schema.unflatten(fstruct)

Either an appstruct or a cstruct can be flattened or unflattened in this way.

Accessing and Mutating Nodes in a Data Structure

colander.SchemaNode.get_value and colander.SchemaNode.set_value can be used to access and mutate nodes in an appstruct or cstruct. Using the example from above:

1
2
3
4
5
  # How much do I like Joe?
  rank = schema.get_value(appstruct, 'friends.2.rank')

  # Joe bought me beer. Let's promote Joe.
  schema.set_value(appstruct, 'friends.2.rank', rank + 5000)