nodes: 0, module; 1, function_definition; 2, function_name:sort; 3, parameters; 4, block; 5, identifier:self; 6, identifier:key; 7, default_parameter; 8, expression_statement; 9, if_statement; 10, return_statement; 11, identifier:reverse; 12, False; 13, comment:"""Sort Table in place, using given fields as sort key.
             @param key: if this is a string, it is a comma-separated list of field names,
                optionally followed by 'desc' to indicate descending sort instead of the 
                default ascending sort; if a list or tuple, it is a list or tuple of field names
                or field names with ' desc' appended; if it is a function, then it is the 
                function to be used as the sort key function
             @param reverse: (default=False) set to True if results should be in reverse order
             @type reverse: bool
             @return: self
          """; 14, call; 15, block; 16, else_clause; 17, identifier:self; 18, identifier:isinstance; 19, argument_list; 20, if_statement; 21, expression_statement; 22, comment:# special optimization if all orders are ascending or descending; 23, if_statement; 24, comment:# sorting given a sort key function; 25, block; 26, identifier:key; 27, tuple; 28, call; 29, block; 30, else_clause; 31, assignment; 32, call; 33, block; 34, elif_clause; 35, else_clause; 36, expression_statement; 37, expression_statement; 38, identifier:basestring; 39, identifier:list; 40, identifier:tuple; 41, identifier:isinstance; 42, argument_list; 43, expression_statement; 44, expression_statement; 45, comment:# attr definitions were already resolved to a sequence by the caller; 46, block; 47, identifier:attrs; 48, list_comprehension; 49, identifier:all; 50, generator_expression; 51, expression_statement; 52, call; 53, block; 54, comment:# mix of ascending and descending sorts, have to do succession of sorts; 55, comment:# leftmost attr is the most primary sort key, so reverse attr_orders to do; 56, comment:# succession of sorts from right to left; 57, block; 58, assignment; 59, call; 60, identifier:key; 61, identifier:basestring; 62, assignment; 63, assignment; 64, if_statement; 65, identifier:attr; 66, for_in_clause; 67, comparison_operator:order == 'asc'; 68, for_in_clause; 69, call; 70, identifier:all; 71, generator_expression; 72, expression_statement; 73, expression_statement; 74, identifier:keyfn; 75, identifier:key; 76, attribute; 77, argument_list; 78, identifier:attrdefs; 79, list_comprehension; 80, identifier:attr_orders; 81, list_comprehension; 82, call; 83, block; 84, else_clause; 85, pattern_list; 86, identifier:attr_orders; 87, identifier:order; 88, string; 89, pattern_list; 90, identifier:attr_orders; 91, attribute; 92, argument_list; 93, comparison_operator:order == 'desc'; 94, for_in_clause; 95, call; 96, call; 97, attribute; 98, identifier:sort; 99, keyword_argument; 100, keyword_argument; 101, call; 102, for_in_clause; 103, subscript; 104, for_in_clause; 105, identifier:isinstance; 106, argument_list; 107, expression_statement; 108, block; 109, identifier:attr; 110, identifier:order; 111, string_content:asc; 112, identifier:attr; 113, identifier:order; 114, attribute; 115, identifier:sort; 116, keyword_argument; 117, keyword_argument; 118, identifier:order; 119, string; 120, pattern_list; 121, identifier:attr_orders; 122, attribute; 123, argument_list; 124, identifier:do_all; 125, generator_expression; 126, identifier:self; 127, identifier:obs; 128, identifier:key; 129, identifier:keyfn; 130, identifier:reverse; 131, identifier:reverse; 132, attribute; 133, argument_list; 134, identifier:s; 135, call; 136, parenthesized_expression; 137, slice; 138, identifier:a; 139, identifier:attrdefs; 140, subscript; 141, identifier:basestring; 142, assignment; 143, expression_statement; 144, identifier:self; 145, identifier:obs; 146, identifier:key; 147, call; 148, identifier:reverse; 149, identifier:reverse; 150, string_content:desc; 151, identifier:attr; 152, identifier:order; 153, attribute; 154, identifier:sort; 155, keyword_argument; 156, keyword_argument; 157, call; 158, for_in_clause; 159, identifier:s; 160, identifier:strip; 161, attribute; 162, argument_list; 163, binary_operator:a.split()+['asc', ]; 164, integer:2; 165, identifier:key; 166, integer:0; 167, identifier:attr_orders; 168, list_comprehension; 169, assignment; 170, identifier:attrgetter; 171, argument_list; 172, identifier:self; 173, identifier:obs; 174, identifier:key; 175, call; 176, identifier:reverse; 177, not_operator; 178, attribute; 179, argument_list; 180, pattern_list; 181, call; 182, identifier:key; 183, identifier:split; 184, string; 185, call; 186, list; 187, subscript; 188, for_in_clause; 189, identifier:attr_orders; 190, identifier:key; 191, list_splat; 192, identifier:attrgetter; 193, argument_list; 194, identifier:reverse; 195, attribute; 196, identifier:sort; 197, keyword_argument; 198, keyword_argument; 199, identifier:attr; 200, identifier:order; 201, identifier:reversed; 202, argument_list; 203, string_content:,; 204, attribute; 205, argument_list; 206, string; 207, parenthesized_expression; 208, slice; 209, identifier:a; 210, identifier:key; 211, identifier:attrs; 212, list_splat; 213, identifier:self; 214, identifier:obs; 215, identifier:key; 216, call; 217, identifier:reverse; 218, parenthesized_expression; 219, identifier:attr_orders; 220, identifier:a; 221, identifier:split; 222, string_content:asc; 223, binary_operator:a.split()+['asc', ]; 224, integer:2; 225, identifier:attrs; 226, identifier:attrgetter; 227, argument_list; 228, comparison_operator:order == "desc"; 229, call; 230, list; 231, identifier:attr; 232, identifier:order; 233, string:"desc"; 234, attribute; 235, argument_list; 236, string; 237, identifier:a; 238, identifier:split; 239, string_content:asc
code: def sort(self, key, reverse=False):
          """Sort Table in place, using given fields as sort key.
             @param key: if this is a string, it is a comma-separated list of field names,
                optionally followed by 'desc' to indicate descending sort instead of the 
                default ascending sort; if a list or tuple, it is a list or tuple of field names
                or field names with ' desc' appended; if it is a function, then it is the 
                function to be used as the sort key function
             @param reverse: (default=False) set to True if results should be in reverse order
             @type reverse: bool
             @return: self
          """
          if isinstance(key, (basestring, list, tuple)):
              if isinstance(key, basestring):
                  attrdefs = [s.strip() for s in key.split(',')]
                  attr_orders = [(a.split()+['asc', ])[:2] for a in attrdefs]
              else:
                  # attr definitions were already resolved to a sequence by the caller
                  if isinstance(key[0], basestring):
                      attr_orders = [(a.split()+['asc', ])[:2] for a in key]
                  else:
                      attr_orders = key
              attrs = [attr for attr, order in attr_orders]
  
              # special optimization if all orders are ascending or descending
              if all(order == 'asc' for attr, order in attr_orders):
                  self.obs.sort(key=attrgetter(*attrs), reverse=reverse)
              elif all(order == 'desc' for attr, order in attr_orders):
                  self.obs.sort(key=attrgetter(*attrs), reverse=not reverse)
              else:
                  # mix of ascending and descending sorts, have to do succession of sorts
                  # leftmost attr is the most primary sort key, so reverse attr_orders to do
                  # succession of sorts from right to left
                  do_all(self.obs.sort(key=attrgetter(attr), reverse=(order == "desc"))
                         for attr, order in reversed(attr_orders))
          else:
              # sorting given a sort key function
              keyfn = key
              self.obs.sort(key=keyfn, reverse=reverse)
          return self