title: PyYAML custom tag for tuple of tuples
body: <p>I'm planning to use PyYAML for a configuration file. Some of the items
  in that configuration file are Python tuples of tuples. So, I need a
  convenient way to represent them. One can represent Python tuples of
  tuples as follows using PyYAML</p>
  
  <pre><code>print yaml.load("!!python/tuple [ !!python/tuple [1, 2], !!python/tuple [3, 4]]")
  </code></pre>
  
  <p>However, this is not convenient notation for a long sequence of
  items. I think it should be possible to define a custom tag, like
  python/tuple_of_tuples. I.e. something like</p>
  
  <pre><code>yaml.load("!!python/tuple_of_tuples [[1,2], [3,4]]")
  </code></pre>
  
  <p>See my first attempt to define this below, by mimicking how
  python/tuple is defined, and trying to do similar subclassing. It
  fails, but gives an idea what I am after, I think. I have a second
  attempt that works, but is a cheat, since it just calls <code>eval</code>.</p>
  
  <p>If I can't find anything better I'll just use that. However, YAML is
  intended as a replacement for ConfigObj, which uses INI files, and is
  considerably less powerful than YAML, and I used the same approach
  (namely <code>eval</code>) for tuples of tuples. So in that respect it will be no
  worse.</p>
  
  <p>A proper solution would be most welcome.</p>
  
  <p>I have a couple of comments on my first solution.</p>
  
  <ol>
  <li><p>I'd have thought that the constructor
  <code>construct_python_tuple_of_tuples</code> would return the completed
  structure, but in fact it seems to return an empty structure as
  follows</p>
  
  <pre><code>([], [])
  </code></pre>
  
  <p>I traced the calls, and there seems to be a lot of complicated stuff
  happening after <code>construct_python_tuple_of_tuples</code> is called.</p>
  
  <p>The value that  is returned is a tuple of lists  of integers, so quite
  close  to the  desired result.  So,  the structure  must be  completed
  later.</p>
  
  <p>The line with</p>
  
  <pre><code>tuple([tuple(t) for t in x])
  </code></pre>
  
  <p>was my attempt to coerce the list of tuples to a tuple of tuples, but
  if I return that from <code>construct_python_tuple_of_tuples</code>, then the
  resulting call to <code>yaml.load("!!python/tuple_of_tuples [[1,2], [3,4]]")</code> is just</p>
  
  <pre><code>((),())
  </code></pre></li>
  <li><p>Not sure what is with the</p>
  
  <pre><code>yaml.org,2002
  </code></pre>
  
  <p>Why 2002?</p></li>
  </ol>
  
  <h3>First attempt</h3>
  
  <pre><code>import yaml
  from yaml.constructor import Constructor
  
  def construct_python_tuple_of_tuples(self, node):
       # Complete content of construct_python_tuple
       # is
       # return tuple(self.construct_sequence(node))
  
       print "node", node
       x = tuple(self.construct_sequence(node))
       print "x", x
       foo = tuple([tuple(t) for t in x])
       print "foo", foo
       return x
  
  Constructor.construct_python_tuple_of_tuples =
  construct_python_tuple_of_tuples
  
  Constructor.add_constructor(
           u'tag:yaml.org,2002:python/tuple_of_tuples',
           Constructor.construct_python_tuple_of_tuples)
  
  y = yaml.load("!!python/tuple_of_tuples [[1,2], [3,4]]")
  print "y", y, type(y)
  print y[0], type(y[0])
  print y[0][0], type(y[0][0])
  </code></pre>
  
  <p>The results are</p>
  
  <pre><code>node SequenceNode(tag=u'tag:yaml.org,2002:python/tuple_of_tuples',
  value=[SequenceNode(tag=u'tag:yaml.org,2002:seq',
  value=[ScalarNode(tag=u'tag:yaml.org,2002:int', value=u'1'),
  ScalarNode(tag=u'tag:yaml.org,2002:int', value=u'2')]),
  SequenceNode(tag=u'tag:yaml.org,2002:seq',
  value=[ScalarNode(tag=u'tag:yaml.org,2002:int', value=u'3'),
  ScalarNode(tag=u'tag:yaml.org,2002:int', value=u'4')])])
  
  x ([], [])
  
  foo ((), ())
  
  y ([1, 2], [3, 4]) &lt;type 'tuple'&gt;
  
  y[0] [1, 2] &lt;type 'list'&gt;
  
  y[0][0] 1 &lt;type 'int'&gt;
  </code></pre>
  
  <h3>Second attempt</h3>
  
  <pre><code>import yaml
  from yaml import YAMLObject, Loader, Dumper
  
  class TupleOfTuples(YAMLObject):
      yaml_loader = Loader
      yaml_dumper = Dumper
  
      yaml_tag = u'!TupleOfTuples'
      #yaml_flow_style = ...
  
      @classmethod
      def from_yaml(cls, loader, node):
          import ast
          print "node", node
      print "node.value", node.value, type(node.value)
          return ast.literal_eval(node.value)
  
      @classmethod
      def to_yaml(cls, dumper, data):
          return node
  
  t = yaml.load("!TupleOfTuples ((1, 2), (3, 4))")
  print "t", t, type(t)
  </code></pre>
  
  <p>The results are:</p>
  
  <pre><code>node ScalarNode(tag=u'!TupleOfTuples', value=u'((1, 2), (3, 4))')
  node.value ((1, 2), (3, 4)) &lt;type 'unicode'&gt;
  t ((1, 2), (3, 4)) &lt;type 'tuple'&gt;
  </code></pre>