nodes: 0, module; 1, function_definition; 2, function_name:tree_diff; 3, parameters; 4, block; 5, identifier:a; 6, identifier:b; 7, default_parameter; 8, default_parameter; 9, expression_statement; 10, expression_statement; 11, expression_statement; 12, if_statement; 13, return_statement; 14, identifier:n; 15, integer:5; 16, identifier:sort; 17, False; 18, comment:"""Dump any data-structure or object, traverse
      it depth-first in-order and apply a unified diff.
  
      Depth-first in-order is just like structure would be printed.
  
      :param             a: data_structure a
      :param             b: data_structure b
      :param             n: lines of context
      :type              n: int
      :param          sort: sort the data-structure
  
      ATTENTION: Sorting means changing the data-structure. The test-result may
      differ. But in case of dictionaries the results become comparable because
      the sorting negates the hash-algorithms "de-sorting".
  
      >>> a = recursive_sort(freeze([
      ...     'a',
      ...     [3, 4],
      ...     {'a': [3, {'w' : set([4, '3', frozenset([3,5,2])])}]},
      ...     []
      ... ]))
      >>> b = recursive_sort(freeze([
      ...     'a',
      ...     [7, 3],
      ...     {'a': [3, {'w' : set([4, '3', frozenset([2,5,3])])}]},
      ...     []
      ... ]))
      >>> transparent_repr("\\n".join(tree_diff(a, b).split("\\n")[2:]))
      @@ -7,6 +7,6 @@
             'w'),),
           3),
          'a'),),
        'a',
        (3,
      -  4))
      +  7))
  
      >>> a = [
      ...     'a',
      ...     [3, 4],
      ...     {'a': [3, {'w' : set([4, '3', frozenset([3,5,2])])}]},
      ...     []
      ... ]
      >>> b = [
      ...     'a',
      ...     [7, 3],
      ...     {'a': [3, {'w' : set([4, '3', frozenset([2,5,3])])}]},
      ...     []
      ... ]
      >>> transparent_repr("\\n".join(
      ...     tree_diff(a, b, sort=True
      ... ).split("\\n")[2:]))
      @@ -11,6 +11,6 @@
                 '3',
                 4)]),)],
            3)),)],
        'a',
        (3,
      -  4))
      +  7))
  
      """; 19, assignment; 20, assignment; 21, not_operator; 22, block; 23, else_clause; 24, call; 25, identifier:a; 26, call; 27, identifier:b; 28, call; 29, identifier:sort; 30, expression_statement; 31, expression_statement; 32, block; 33, attribute; 34, argument_list; 35, identifier:dump; 36, argument_list; 37, identifier:dump; 38, argument_list; 39, assignment; 40, assignment; 41, expression_statement; 42, expression_statement; 43, string:"\n"; 44, identifier:join; 45, call; 46, identifier:a; 47, identifier:b; 48, identifier:a; 49, call; 50, identifier:b; 51, call; 52, assignment; 53, assignment; 54, attribute; 55, argument_list; 56, attribute; 57, argument_list; 58, attribute; 59, argument_list; 60, identifier:a; 61, call; 62, identifier:b; 63, call; 64, identifier:difflib; 65, identifier:unified_diff; 66, identifier:a; 67, identifier:b; 68, keyword_argument; 69, keyword_argument; 70, call; 71, identifier:split; 72, string:"\n"; 73, call; 74, identifier:split; 75, string:"\n"; 76, attribute; 77, argument_list; 78, attribute; 79, argument_list; 80, identifier:n; 81, identifier:n; 82, identifier:lineterm; 83, string:""; 84, identifier:vformat; 85, argument_list; 86, identifier:vformat; 87, argument_list; 88, call; 89, identifier:split; 90, string:"\n"; 91, call; 92, identifier:split; 93, string:"\n"; 94, identifier:a; 95, identifier:b; 96, identifier:vformat; 97, argument_list; 98, identifier:vformat; 99, argument_list; 100, call; 101, call; 102, identifier:recursive_sort; 103, argument_list; 104, identifier:recursive_sort; 105, argument_list; 106, identifier:a; 107, identifier:b
code: def tree_diff(a, b, n=5, sort=False):
      """Dump any data-structure or object, traverse
      it depth-first in-order and apply a unified diff.
  
      Depth-first in-order is just like structure would be printed.
  
      :param             a: data_structure a
      :param             b: data_structure b
      :param             n: lines of context
      :type              n: int
      :param          sort: sort the data-structure
  
      ATTENTION: Sorting means changing the data-structure. The test-result may
      differ. But in case of dictionaries the results become comparable because
      the sorting negates the hash-algorithms "de-sorting".
  
      >>> a = recursive_sort(freeze([
      ...     'a',
      ...     [3, 4],
      ...     {'a': [3, {'w' : set([4, '3', frozenset([3,5,2])])}]},
      ...     []
      ... ]))
      >>> b = recursive_sort(freeze([
      ...     'a',
      ...     [7, 3],
      ...     {'a': [3, {'w' : set([4, '3', frozenset([2,5,3])])}]},
      ...     []
      ... ]))
      >>> transparent_repr("\\n".join(tree_diff(a, b).split("\\n")[2:]))
      @@ -7,6 +7,6 @@
             'w'),),
           3),
          'a'),),
        'a',
        (3,
      -  4))
      +  7))
  
      >>> a = [
      ...     'a',
      ...     [3, 4],
      ...     {'a': [3, {'w' : set([4, '3', frozenset([3,5,2])])}]},
      ...     []
      ... ]
      >>> b = [
      ...     'a',
      ...     [7, 3],
      ...     {'a': [3, {'w' : set([4, '3', frozenset([2,5,3])])}]},
      ...     []
      ... ]
      >>> transparent_repr("\\n".join(
      ...     tree_diff(a, b, sort=True
      ... ).split("\\n")[2:]))
      @@ -11,6 +11,6 @@
                 '3',
                 4)]),)],
            3)),)],
        'a',
        (3,
      -  4))
      +  7))
  
      """
      a = dump(a)
      b = dump(b)
      if not sort:
          a = vformat(a).split("\n")
          b = vformat(b).split("\n")
      else:
          a = vformat(recursive_sort(a)).split("\n")
          b = vformat(recursive_sort(b)).split("\n")
      return "\n".join(difflib.unified_diff(a, b, n=n, lineterm=""))