nodes: 0, module; 1, function_definition; 2, function_name:ask_choice; 3, parameters; 4, type; 5, block; 6, typed_parameter; 7, typed_parameter; 8, typed_default_parameter; 9, identifier:Any; 10, expression_statement; 11, if_statement; 12, expression_statement; 13, expression_statement; 14, expression_statement; 15, for_statement; 16, expression_statement; 17, expression_statement; 18, while_statement; 19, return_statement; 20, list_splat_pattern; 21, type; 22, identifier:choices; 23, type; 24, identifier:func_desc; 25, type; 26, None; 27, comment:"""Ask the user to choose from a list of choices.
  
      :return: the selected choice
  
      ``func_desc`` will be called on every list item for displaying
      and sorting the list. If not given, will default to
      the identity function.
  
      Will loop until:
          * the user enters a valid index
          * or leaves the prompt empty
  
      In the last case, None will be returned
      """; 28, comparison_operator:func_desc is None; 29, block; 30, assignment; 31, call; 32, call; 33, pattern_list; 34, call; 35, block; 36, assignment; 37, assignment; 38, identifier:keep_asking; 39, block; 40, identifier:res; 41, identifier:prompt; 42, identifier:Token; 43, generic_type; 44, generic_type; 45, identifier:func_desc; 46, None; 47, expression_statement; 48, identifier:tokens; 49, call; 50, identifier:info; 51, argument_list; 52, attribute; 53, argument_list; 54, identifier:i; 55, identifier:choice; 56, identifier:enumerate; 57, argument_list; 58, expression_statement; 59, expression_statement; 60, identifier:keep_asking; 61, True; 62, identifier:res; 63, None; 64, expression_statement; 65, if_statement; 66, try_statement; 67, if_statement; 68, expression_statement; 69, expression_statement; 70, identifier:List; 71, type_parameter; 72, identifier:Optional; 73, type_parameter; 74, assignment; 75, identifier:get_ask_tokens; 76, argument_list; 77, list_splat; 78, identifier:choices; 79, identifier:sort; 80, keyword_argument; 81, identifier:choices; 82, keyword_argument; 83, assignment; 84, call; 85, assignment; 86, not_operator; 87, block; 88, block; 89, except_clause; 90, comparison_operator:index not in range(1, len(choices) + 1); 91, block; 92, assignment; 93, assignment; 94, type; 95, type; 96, identifier:func_desc; 97, lambda; 98, identifier:prompt; 99, identifier:tokens; 100, identifier:key; 101, identifier:func_desc; 102, identifier:start; 103, integer:1; 104, identifier:choice_desc; 105, call; 106, identifier:info; 107, argument_list; 108, identifier:answer; 109, call; 110, identifier:answer; 111, return_statement; 112, expression_statement; 113, identifier:ValueError; 114, block; 115, identifier:index; 116, call; 117, expression_statement; 118, continue_statement; 119, identifier:res; 120, subscript; 121, identifier:keep_asking; 122, False; 123, identifier:Any; 124, identifier:FuncDesc; 125, lambda_parameters; 126, call; 127, identifier:func_desc; 128, argument_list; 129, string:"  "; 130, identifier:blue; 131, binary_operator:"%i" % i; 132, identifier:reset; 133, identifier:choice_desc; 134, identifier:read_input; 135, argument_list; 136, None; 137, assignment; 138, expression_statement; 139, continue_statement; 140, identifier:range; 141, argument_list; 142, call; 143, identifier:choices; 144, binary_operator:index - 1; 145, identifier:x; 146, identifier:str; 147, argument_list; 148, identifier:choice; 149, string:"%i"; 150, identifier:i; 151, identifier:index; 152, call; 153, call; 154, integer:1; 155, binary_operator:len(choices) + 1; 156, identifier:info; 157, argument_list; 158, identifier:index; 159, integer:1; 160, identifier:x; 161, identifier:int; 162, argument_list; 163, identifier:info; 164, argument_list; 165, call; 166, integer:1; 167, call; 168, string:"is out of range"; 169, identifier:answer; 170, string:"Please enter a valid number"; 171, identifier:len; 172, argument_list; 173, identifier:str; 174, argument_list; 175, identifier:choices; 176, identifier:index
code: def ask_choice(
      *prompt: Token, choices: List[Any], func_desc: Optional[FuncDesc] = None
  ) -> Any:
      """Ask the user to choose from a list of choices.
  
      :return: the selected choice
  
      ``func_desc`` will be called on every list item for displaying
      and sorting the list. If not given, will default to
      the identity function.
  
      Will loop until:
          * the user enters a valid index
          * or leaves the prompt empty
  
      In the last case, None will be returned
      """
      if func_desc is None:
          func_desc = lambda x: str(x)
      tokens = get_ask_tokens(prompt)
      info(*tokens)
      choices.sort(key=func_desc)
      for i, choice in enumerate(choices, start=1):
          choice_desc = func_desc(choice)
          info("  ", blue, "%i" % i, reset, choice_desc)
      keep_asking = True
      res = None
      while keep_asking:
          answer = read_input()
          if not answer:
              return None
          try:
              index = int(answer)
          except ValueError:
              info("Please enter a valid number")
              continue
          if index not in range(1, len(choices) + 1):
              info(str(index), "is out of range")
              continue
          res = choices[index - 1]
          keep_asking = False
  
      return res