nodes: 0, module; 1, function_definition; 2, function_name:select_best_url; 3, parameters; 4, block; 5, identifier:self; 6, expression_statement; 7, expression_statement; 8, try_statement; 9, comment:"""Select `best` url.
  
      Since urls are pre-sorted w.r.t. their ping times, we simply return the first element
      from the list. And we always return the same url unless we observe greater than max
      allowed number of consecutive failures. In this case, we would return the next `best`
      url, and append the previous best one to the end of list (essentially rotate to the left
      by one element).
      """; 10, assignment; 11, block; 12, except_clause; 13, else_clause; 14, identifier:best_url; 15, subscript; 16, expression_statement; 17, identifier:Exception; 18, block; 19, block; 20, attribute; 21, integer:0; 22, yield; 23, expression_statement; 24, comment:# Not thread-safe but pool used by cache is based on subprocesses, therefore no race.; 25, if_statement; 26, raise_statement; 27, expression_statement; 28, identifier:self; 29, identifier:parsed_urls; 30, identifier:best_url; 31, augmented_assignment; 32, comparison_operator:self.unsuccessful_calls[best_url] > self.max_failures; 33, block; 34, assignment; 35, subscript; 36, integer:1; 37, subscript; 38, attribute; 39, expression_statement; 40, expression_statement; 41, subscript; 42, integer:0; 43, attribute; 44, identifier:best_url; 45, attribute; 46, identifier:best_url; 47, identifier:self; 48, identifier:max_failures; 49, call; 50, assignment; 51, attribute; 52, identifier:best_url; 53, identifier:self; 54, identifier:unsuccessful_calls; 55, identifier:self; 56, identifier:unsuccessful_calls; 57, attribute; 58, argument_list; 59, subscript; 60, integer:0; 61, identifier:self; 62, identifier:unsuccessful_calls; 63, attribute; 64, identifier:rotate; 65, unary_operator; 66, attribute; 67, identifier:best_url; 68, identifier:self; 69, identifier:parsed_urls; 70, integer:1; 71, identifier:self; 72, identifier:unsuccessful_calls
code: def select_best_url(self):
      """Select `best` url.
  
      Since urls are pre-sorted w.r.t. their ping times, we simply return the first element
      from the list. And we always return the same url unless we observe greater than max
      allowed number of consecutive failures. In this case, we would return the next `best`
      url, and append the previous best one to the end of list (essentially rotate to the left
      by one element).
      """
  
      best_url = self.parsed_urls[0]
      try:
        yield best_url
      except Exception:
        self.unsuccessful_calls[best_url] += 1
  
        # Not thread-safe but pool used by cache is based on subprocesses, therefore no race.
        if self.unsuccessful_calls[best_url] > self.max_failures:
          self.parsed_urls.rotate(-1)
          self.unsuccessful_calls[best_url] = 0
        raise
      else:
        self.unsuccessful_calls[best_url] = 0