def recurse(desc, pre='<STR_LIT>', post=None, python_path=None):
def call(f, desc):<EOL><INDENT>if isinstance(f, str):<EOL><INDENT>f = getattr(datatype, f, None)<EOL><DEDENT>return f and f(desc)<EOL><DEDENT>desc = load.load_if_filename(desc) or desc<EOL>desc = construct.to_type_constructor(desc, python_path)<EOL>datatype = desc.get('<STR_LIT>')<EOL>desc = call(pre, desc) or desc<EOL>for child_name in getattr(datatype, '<STR_LIT>', []):<EOL><INDENT>child = desc.get(child_name)<EOL>if child:<EOL><INDENT>is_plural = child_name.endswith('<STR_LIT:s>')<EOL>remove_s = is_plural and child_name != '<STR_LIT>'<EOL>cname = child_name[:-<NUM_LIT:1>] if remove_s else child_name<EOL>new_path = python_path or ('<STR_LIT>' + cname)<EOL>if is_plural:<EOL><INDENT>if isinstance(child, (dict, str)):<EOL><INDENT>child = [child]<EOL><DEDENT>for i, c in enumerate(child):<EOL><INDENT>child[i] = recurse(c, pre, post, new_path)<EOL><DEDENT>desc[child_name] = child<EOL><DEDENT>else:<EOL><INDENT>desc[child_name] = recurse(child, pre, post, new_path)<EOL><DEDENT><DEDENT><DEDENT>d = call(post, desc)<EOL>return desc if d is None else d<EOL>
Depth first recursion through a dictionary containing type constructors

The arguments pre, post and children are independently either:

* None, which means to do nothing
* a string, which means to use the static class method of that name on the
  class being constructed, or
* a callable, to be called at each recursion

Arguments:

dictionary -- a project dictionary or one of its subdictionaries
pre -- called before children are visited node in the recursion
post -- called after children are visited in the recursion
python_path -- relative path to start resolving typenames