nodes: 0, module; 1, function_definition; 2, function_name:sort_resources; 3, parameters; 4, block; 5, identifier:cls; 6, identifier:request; 7, identifier:resources; 8, identifier:fail_enum; 9, default_parameter; 10, expression_statement; 11, if_statement; 12, expression_statement; 13, function_definition; 14, return_statement; 15, identifier:header_proto; 16, None; 17, comment:"""Sorts a list of resources based on a list of sort controls
  
          Args:
              request (object): The parsed protobuf request object
              resources (list of objects): The resources to be sorted
              fail_enum (int, enum): The enum status to raise with invalid keys
              header_proto(class): Class to decode a resources header
  
          Returns:
              list: The sorted list of resources
          """; 18, not_operator; 19, block; 20, assignment; 21, function_name:sorter; 22, parameters; 23, block; 24, call; 25, attribute; 26, return_statement; 27, identifier:value_handlers; 28, call; 29, identifier:resource_a; 30, identifier:resource_b; 31, for_statement; 32, return_statement; 33, identifier:sorted; 34, argument_list; 35, identifier:request; 36, identifier:sorting; 37, identifier:resources; 38, attribute; 39, argument_list; 40, identifier:handler; 41, identifier:value_handlers; 42, block; 43, integer:0; 44, identifier:resources; 45, keyword_argument; 46, identifier:cls; 47, identifier:_get_handler_set; 48, identifier:request; 49, identifier:fail_enum; 50, identifier:header_proto; 51, expression_statement; 52, if_statement; 53, if_statement; 54, identifier:key; 55, call; 56, assignment; 57, comparison_operator:val_a < val_b; 58, block; 59, comparison_operator:val_a > val_b; 60, block; 61, identifier:cmp_to_key; 62, argument_list; 63, pattern_list; 64, call; 65, identifier:val_a; 66, identifier:val_b; 67, return_statement; 68, identifier:val_a; 69, identifier:val_b; 70, return_statement; 71, identifier:sorter; 72, identifier:val_a; 73, identifier:val_b; 74, attribute; 75, argument_list; 76, call; 77, call; 78, identifier:handler; 79, identifier:get_sort_values; 80, identifier:resource_a; 81, identifier:resource_b; 82, attribute; 83, argument_list; 84, attribute; 85, argument_list; 86, identifier:handler; 87, identifier:xform_result; 88, unary_operator; 89, identifier:handler; 90, identifier:xform_result; 91, integer:1; 92, integer:1
code: def sort_resources(cls, request, resources, fail_enum, header_proto=None):
          """Sorts a list of resources based on a list of sort controls
  
          Args:
              request (object): The parsed protobuf request object
              resources (list of objects): The resources to be sorted
              fail_enum (int, enum): The enum status to raise with invalid keys
              header_proto(class): Class to decode a resources header
  
          Returns:
              list: The sorted list of resources
          """
          if not request.sorting:
              return resources
  
          value_handlers = cls._get_handler_set(request, fail_enum, header_proto)
  
          def sorter(resource_a, resource_b):
              for handler in value_handlers:
                  val_a, val_b = handler.get_sort_values(resource_a, resource_b)
  
                  if val_a < val_b:
                      return handler.xform_result(-1)
                  if val_a > val_b:
                      return handler.xform_result(1)
  
              return 0
  
          return sorted(resources, key=cmp_to_key(sorter))