nodes: 0, module; 1, function_definition; 2, function_name:dimension_sort; 3, parameters; 4, block; 5, identifier:odict; 6, identifier:kdims; 7, identifier:vdims; 8, identifier:key_index; 9, expression_statement; 10, expression_statement; 11, expression_statement; 12, expression_statement; 13, expression_statement; 14, expression_statement; 15, if_statement; 16, if_statement; 17, comment:"""
      Sorts data by key using usual Python tuple sorting semantics
      or sorts in categorical order for any categorical Dimensions.
      """; 18, assignment; 19, assignment; 20, assignment; 21, assignment; 22, assignment; 23, comparison_operator:len(set(key_index)) != len(key_index); 24, block; 25, else_clause; 26, comparison_operator:sys.version_info.major == 3; 27, block; 28, else_clause; 29, identifier:sortkws; 30, dictionary; 31, identifier:ndims; 32, call; 33, identifier:dimensions; 34, binary_operator:kdims+vdims; 35, identifier:indexes; 36, list_comprehension; 37, identifier:cached_values; 38, dictionary_comprehension; 39, call; 40, call; 41, raise_statement; 42, block; 43, attribute; 44, integer:3; 45, return_statement; 46, block; 47, identifier:len; 48, argument_list; 49, identifier:kdims; 50, identifier:vdims; 51, tuple; 52, for_in_clause; 53, pair; 54, for_in_clause; 55, identifier:len; 56, argument_list; 57, identifier:len; 58, argument_list; 59, call; 60, expression_statement; 61, attribute; 62, identifier:major; 63, call; 64, return_statement; 65, identifier:kdims; 66, subscript; 67, call; 68, conditional_expression:i if i in range(ndims) else i-ndims; 69, identifier:i; 70, identifier:key_index; 71, attribute; 72, binary_operator:[None]+list(d.values); 73, identifier:d; 74, identifier:dimensions; 75, call; 76, identifier:key_index; 77, identifier:ValueError; 78, argument_list; 79, assignment; 80, identifier:sys; 81, identifier:version_info; 82, identifier:python2sort; 83, argument_list; 84, call; 85, identifier:dimensions; 86, identifier:i; 87, identifier:int; 88, argument_list; 89, identifier:i; 90, comparison_operator:i in range(ndims); 91, binary_operator:i-ndims; 92, identifier:d; 93, identifier:name; 94, list; 95, call; 96, identifier:set; 97, argument_list; 98, string:"Cannot sort on duplicated dimensions"; 99, subscript; 100, lambda; 101, call; 102, dictionary_splat; 103, identifier:sorted; 104, argument_list; 105, comparison_operator:i not in range(ndims); 106, identifier:i; 107, call; 108, identifier:i; 109, identifier:ndims; 110, None; 111, identifier:list; 112, argument_list; 113, identifier:key_index; 114, identifier:sortkws; 115, string; 116, lambda_parameters; 117, call; 118, attribute; 119, argument_list; 120, identifier:sortkws; 121, call; 122, dictionary_splat; 123, identifier:i; 124, call; 125, identifier:range; 126, argument_list; 127, attribute; 128, string_content:key; 129, identifier:x; 130, identifier:tuple; 131, generator_expression; 132, identifier:odict; 133, identifier:items; 134, attribute; 135, argument_list; 136, identifier:sortkws; 137, identifier:range; 138, argument_list; 139, identifier:ndims; 140, identifier:d; 141, identifier:values; 142, conditional_expression:cached_values[dim.name].index(x[t][d])
                                          if dim.values else x[t][d]; 143, for_in_clause; 144, identifier:odict; 145, identifier:items; 146, identifier:ndims; 147, call; 148, attribute; 149, subscript; 150, pattern_list; 151, call; 152, attribute; 153, argument_list; 154, identifier:dim; 155, identifier:values; 156, subscript; 157, identifier:d; 158, identifier:i; 159, tuple_pattern; 160, identifier:enumerate; 161, argument_list; 162, subscript; 163, identifier:index; 164, subscript; 165, identifier:x; 166, identifier:t; 167, identifier:dim; 168, identifier:t; 169, identifier:d; 170, identifier:indexes; 171, identifier:cached_values; 172, attribute; 173, subscript; 174, identifier:d; 175, identifier:dim; 176, identifier:name; 177, identifier:x; 178, identifier:t
code: def dimension_sort(odict, kdims, vdims, key_index):
      """
      Sorts data by key using usual Python tuple sorting semantics
      or sorts in categorical order for any categorical Dimensions.
      """
      sortkws = {}
      ndims = len(kdims)
      dimensions = kdims+vdims
      indexes = [(dimensions[i], int(i not in range(ndims)),
                      i if i in range(ndims) else i-ndims)
                  for i in key_index]
      cached_values = {d.name: [None]+list(d.values) for d in dimensions}
  
      if len(set(key_index)) != len(key_index):
          raise ValueError("Cannot sort on duplicated dimensions")
      else:
         sortkws['key'] = lambda x: tuple(cached_values[dim.name].index(x[t][d])
                                          if dim.values else x[t][d]
                                          for i, (dim, t, d) in enumerate(indexes))
      if sys.version_info.major == 3:
          return python2sort(odict.items(), **sortkws)
      else:
          return sorted(odict.items(), **sortkws)